DO NOT MERGE Restore libcorkscrew unwinding.
automerge: 5a69c1d  -s ours

* commit '5a69c1db365323f984c6a8afd1fc035551e96d99':
  DO NOT MERGE Restore libcorkscrew unwinding.
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 74ec29d..0254bd2 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -51,3 +51,5 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/init.rc)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/init.rc)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/reboot)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/default.prop)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/default.prop)
diff --git a/adb/Android.mk b/adb/Android.mk
index 62f012c..50e28a6 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -74,7 +74,7 @@
   LOCAL_SRC_FILES += fdevent.c
 endif
 
-LOCAL_CFLAGS += -O2 -g -DADB_HOST=1  -Wall -Wno-unused-parameter
+LOCAL_CFLAGS += -O2 -g -DADB_HOST=1 -Wall -Wno-unused-parameter -Werror
 LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
 LOCAL_MODULE := adb
 LOCAL_MODULE_TAGS := debug
@@ -116,7 +116,7 @@
 	remount_service.c \
 	usb_linux_client.c
 
-LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter
+LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter -Werror
 LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
 
 ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
@@ -138,8 +138,6 @@
 ifneq ($(SDK_ONLY),true)
 include $(CLEAR_VARS)
 
-LOCAL_LDLIBS := -lrt -ldl -lpthread
-
 LOCAL_SRC_FILES := \
 	adb.c \
 	console.c \
@@ -162,8 +160,7 @@
 	-g \
 	-DADB_HOST=1 \
 	-DADB_HOST_ON_TARGET=1 \
-	-Wall \
-	-Wno-unused-parameter \
+	-Wall -Wno-unused-parameter -Werror \
 	-D_XOPEN_SOURCE \
 	-D_GNU_SOURCE
 
diff --git a/adb/SERVICES.TXT b/adb/SERVICES.TXT
index 7f85dc3..63000f2 100644
--- a/adb/SERVICES.TXT
+++ b/adb/SERVICES.TXT
@@ -240,3 +240,20 @@
     This starts the file synchronisation service, used to implement "adb push"
     and "adb pull". Since this service is pretty complex, it will be detailed
     in a companion document named SYNC.TXT
+
+reverse:<forward-command>
+    This implements the 'adb reverse' feature, i.e. the ability to reverse
+    socket connections from a device to the host. <forward-command> is one
+    of the forwarding commands that are described above, as in:
+
+      list-forward
+      forward:<local>;<remote>
+      forward:norebind:<local>;<remote>
+      killforward-all
+      killforward:<local>
+
+    Note that in this case, <local> corresponds to the socket on the device
+    and <remote> corresponds to the socket on the host.
+
+    The output of reverse:list-forward is the same as host:list-forward
+    except that <serial> will be just 'host'.
diff --git a/adb/SYNC.TXT b/adb/SYNC.TXT
new file mode 100644
index 0000000..e74d217
--- /dev/null
+++ b/adb/SYNC.TXT
@@ -0,0 +1,84 @@
+This file tries to document file related requests a client can make
+to the ADB server of an adbd daemon. See the OVERVIEW.TXT document
+to understand what's going on here. See the SERVICES.TXT to learn more
+about the other requests that are possible.
+
+SYNC SERVICES:
+
+
+Requesting the sync service ("sync:") using the protocol as described in
+SERVICES.TXT sets the connection in sync mode. This mode is a binary mode that
+differ from the regular adb protocol. The connection stays in sync mode until
+explicitly terminated (see below).
+
+After the initial "sync:" command is sent the server must respond with either
+"OKAY" or "FAIL" as per usual. 
+
+In sync mode both the server and the client will frequently use eight-byte
+packets to communicate in this document called sync request and sync
+responses. The first four bytes is an id and specifies sync request is
+represented by four utf-8 characters. The last four bytes is a Little-Endian
+integer, with various uses. This number will be called "length" below. In fact
+all binary integers are Little-Endian in the sync mode. Sync mode is
+implicitly exited after each sync request, and normal adb communication
+follows as described in SERVICES.TXT.
+
+The following sync requests are accepted:
+LIST - List the files in a folder
+SEND - Send a file to device
+RECV - Retreive a file from device
+
+Not yet documented:
+STAT - Stat a file
+ULNK - Unlink (remove) a file. (Not currently supported)
+
+For all of the sync request above the must be followed by length number of
+bytes containing an utf-8 string with a remote filename.
+
+LIST:
+Lists files in the directory specified by the remote filename. The server will
+respond with zero or more directory entries or "dents".
+
+The directory entries will be returned in the following form
+1. A four-byte sync response id beeing "DENT"
+2. A four-byte integer representing file mode.
+3. A four-byte integer representing file size.
+4. A four-byte integer representing last modified time.
+5. A four-byte integer representing file name length.
+6. length number of bytes containing an utf-8 string representing the file
+   name.
+
+When an sync response "DONE" is received the listing is done.
+
+SEND:
+The remote file name is split into two parts separated by the last
+comma (","). The first part is the actual path, while the second is a decimal
+encoded file mode containing the permissions of the file on device.
+
+Note that some file types will be deleted before the copying starts, and if
+the transfer fails. Some file types will not be deleted, which allows
+  adb push disk_image /some_block_device
+to work.
+
+After this the actual file is sent in chunks. Each chucks has the following
+format.
+A sync request with id "DATA" and length equal to the chunk size. After
+follows chunk size number of bytes. This is repeated until the file is
+transfered. Each chunk must not be larger than 64k.
+
+When the file is tranfered a sync request "DONE" is sent, where length is set
+to the last modified time for the file. The server responds to this last
+request (but not to chuck requests) with an "OKAY" sync response (length can
+be ignored).
+
+
+RECV:
+Retrieves a file from device to a local file. The remote path is the path to
+the file that will be returned. Just as for the SEND sync request the file
+received is split up into chunks. The sync response id is "DATA" and length is
+the chuck size. After follows chunk size number of bytes. This is repeated
+until the file is transfered. Each chuck will not be larger than 64k.
+
+When the file is transfered a sync resopnse "DONE" is retrieved where the
+length can be ignored.
+
diff --git a/adb/adb.c b/adb/adb.c
index e116414..90bdbaa 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -318,6 +318,26 @@
 #endif
 }
 
+#if !ADB_HOST
+static void send_msg_with_header(int fd, const char* msg, size_t msglen) {
+    char header[5];
+    if (msglen > 0xffff)
+        msglen = 0xffff;
+    snprintf(header, sizeof(header), "%04x", (unsigned)msglen);
+    writex(fd, header, 4);
+    writex(fd, msg, msglen);
+}
+#endif
+
+static void send_msg_with_okay(int fd, const char* msg, size_t msglen) {
+    char header[9];
+    if (msglen > 0xffff)
+        msglen = 0xffff;
+    snprintf(header, sizeof(header), "OKAY%04x", (unsigned)msglen);
+    writex(fd, header, 8);
+    writex(fd, msg, msglen);
+}
+
 static void send_connect(atransport *t)
 {
     D("Calling send_connect \n");
@@ -1324,29 +1344,29 @@
           " unchanged.\n");
     }
 
+    /* add extra groups:
+    ** AID_ADB to access the USB driver
+    ** AID_LOG to read system logs (adb logcat)
+    ** AID_INPUT to diagnose input issues (getevent)
+    ** AID_INET to diagnose network issues (netcfg, ping)
+    ** AID_GRAPHICS to access the frame buffer
+    ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
+    ** AID_SDCARD_R to allow reading from the SD card
+    ** AID_SDCARD_RW to allow writing to the SD card
+    ** AID_NET_BW_STATS to read out qtaguid statistics
+    */
+    gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS,
+                       AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
+                       AID_NET_BW_STATS };
+    if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
+        exit(1);
+    }
+
     /* don't listen on a port (default 5037) if running in secure mode */
     /* don't run as root if we are running in secure mode */
     if (should_drop_privileges()) {
         drop_capabilities_bounding_set_if_needed();
 
-        /* add extra groups:
-        ** AID_ADB to access the USB driver
-        ** AID_LOG to read system logs (adb logcat)
-        ** AID_INPUT to diagnose input issues (getevent)
-        ** AID_INET to diagnose network issues (netcfg, ping)
-        ** AID_GRAPHICS to access the frame buffer
-        ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
-        ** AID_SDCARD_R to allow reading from the SD card
-        ** AID_SDCARD_RW to allow writing to the SD card
-        ** AID_NET_BW_STATS to read out qtaguid statistics
-        */
-        gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS,
-                           AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
-                           AID_NET_BW_STATS };
-        if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
-            exit(1);
-        }
-
         /* then switch user and group to "shell" */
         if (setgid(AID_SHELL) != 0) {
             exit(1);
@@ -1418,10 +1438,123 @@
     return 0;
 }
 
+// Try to handle a network forwarding request.
+// This returns 1 on success, 0 on failure, and -1 to indicate this is not
+// a forwarding-related request.
+int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd)
+{
+    if (!strcmp(service, "list-forward")) {
+        // Create the list of forward redirections.
+        int buffer_size = format_listeners(NULL, 0);
+        // Add one byte for the trailing zero.
+        char* buffer = malloc(buffer_size + 1);
+        if (buffer == NULL) {
+            sendfailmsg(reply_fd, "not enough memory");
+            return 1;
+        }
+        (void) format_listeners(buffer, buffer_size + 1);
+#if ADB_HOST
+        send_msg_with_okay(reply_fd, buffer, buffer_size);
+#else
+        send_msg_with_header(reply_fd, buffer, buffer_size);
+#endif
+        free(buffer);
+        return 1;
+    }
+
+    if (!strcmp(service, "killforward-all")) {
+        remove_all_listeners();
+#if ADB_HOST
+        /* On the host: 1st OKAY is connect, 2nd OKAY is status */
+        adb_write(reply_fd, "OKAY", 4);
+#endif
+        adb_write(reply_fd, "OKAY", 4);
+        return 1;
+    }
+
+    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 = strchr(service, ':') + 1;
+
+        // Handle forward:norebind:<local>... here
+        if (createForward && !strncmp(local, "norebind:", 9)) {
+            no_rebind = 1;
+            local = strchr(local, ':') + 1;
+        }
+
+        remote = strchr(local,';');
+
+        if (createForward) {
+            // Check forward: parameter format: '<local>;<remote>'
+            if(remote == 0) {
+                sendfailmsg(reply_fd, "malformed forward spec");
+                return 1;
+            }
+
+            *remote++ = 0;
+            if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')) {
+                sendfailmsg(reply_fd, "malformed forward spec");
+                return 1;
+            }
+        } else {
+            // Check killforward: parameter format: '<local>'
+            if (local[0] == 0) {
+                sendfailmsg(reply_fd, "malformed forward spec");
+                return 1;
+            }
+        }
+
+        transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
+        if (!transport) {
+            sendfailmsg(reply_fd, err);
+            return 1;
+        }
+
+        if (createForward) {
+            r = install_listener(local, remote, transport, no_rebind);
+        } else {
+            r = remove_listener(local, transport);
+        }
+        if(r == 0) {
+#if ADB_HOST
+            /* On the host: 1st OKAY is connect, 2nd OKAY is status */
+            writex(reply_fd, "OKAY", 4);
+#endif
+            writex(reply_fd, "OKAY", 4);
+            return 1;
+        }
+
+        if (createForward) {
+            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");
+        }
+        return 1;
+    }
+    return 0;
+}
+
 int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
 {
     atransport *transport = NULL;
-    char buf[4096];
 
     if(!strcmp(service, "kill")) {
         fprintf(stderr,"adb server killed by remote request\n");
@@ -1467,13 +1600,11 @@
         char buffer[4096];
         int use_long = !strcmp(service+7, "-l");
         if (use_long || service[7] == 0) {
-            memset(buf, 0, sizeof(buf));
             memset(buffer, 0, sizeof(buffer));
             D("Getting device list \n");
             list_transports(buffer, sizeof(buffer), use_long);
-            snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer);
             D("Wrote device list \n");
-            writex(reply_fd, buf, strlen(buf));
+            send_msg_with_okay(reply_fd, buffer, strlen(buffer));
             return 0;
         }
     }
@@ -1502,8 +1633,7 @@
             }
         }
 
-        snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer);
-        writex(reply_fd, buf, strlen(buf));
+        send_msg_with_okay(reply_fd, buffer, strlen(buffer));
         return 0;
     }
 
@@ -1511,8 +1641,7 @@
     if (!strcmp(service, "version")) {
         char version[12];
         snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION);
-        snprintf(buf, sizeof buf, "OKAY%04x%s", (unsigned)strlen(version), version);
-        writex(reply_fd, buf, strlen(buf));
+        send_msg_with_okay(reply_fd, version, strlen(version));
         return 0;
     }
 
@@ -1522,8 +1651,7 @@
        if (transport && transport->serial) {
             out = transport->serial;
         }
-        snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out);
-        writex(reply_fd, buf, strlen(buf));
+        send_msg_with_okay(reply_fd, out, strlen(out));
         return 0;
     }
     if(!strncmp(service,"get-devpath",strlen("get-devpath"))) {
@@ -1532,8 +1660,7 @@
        if (transport && transport->devpath) {
             out = transport->devpath;
         }
-        snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out);
-        writex(reply_fd, buf, strlen(buf));
+        send_msg_with_okay(reply_fd, out, strlen(out));
         return 0;
     }
     // indicates a new emulator instance has started
@@ -1545,106 +1672,14 @@
     }
 #endif // ADB_HOST
 
-    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 = strchr(service, ':') + 1;
-
-        // Handle forward:norebind:<local>... here
-        if (createForward && !strncmp(local, "norebind:", 9)) {
-            no_rebind = 1;
-            local = strchr(local, ':') + 1;
-        }
-
-        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);
-        if (!transport) {
-            sendfailmsg(reply_fd, err);
-            return 0;
-        }
-
-        if (createForward) {
-            r = install_listener(local, remote, transport, no_rebind);
-        } else {
-            r = remove_listener(local, transport);
-        }
-        if(r == 0) {
-                /* 1st OKAY is connect, 2nd OKAY is status */
-            writex(reply_fd, "OKAYOKAY", 8);
-            return 0;
-        }
-
-        if (createForward) {
-            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");
-        }
-        return 0;
-    }
+    int ret = handle_forward_request(service, ttype, serial, reply_fd);
+    if (ret >= 0)
+      return ret - 1;
 
     if(!strncmp(service,"get-state",strlen("get-state"))) {
         transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
         char *state = connection_state_name(transport);
-        snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(state),state);
-        writex(reply_fd, buf, strlen(buf));
+        send_msg_with_okay(reply_fd, state, strlen(state));
         return 0;
     }
     return -1;
diff --git a/adb/adb.h b/adb/adb.h
index 6f5c93c..2504f99 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -323,6 +323,8 @@
 int       create_jdwp_connection_fd(int  jdwp_pid);
 #endif
 
+int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd);
+
 #if !ADB_HOST
 typedef enum {
     BACKUP,
diff --git a/adb/adb_auth_host.c b/adb/adb_auth_host.c
index 9039d42..783774a 100644
--- a/adb/adb_auth_host.c
+++ b/adb/adb_auth_host.c
@@ -159,13 +159,13 @@
 
     bio = BIO_push(b64, bfile);
     BIO_write(bio, &pkey, sizeof(pkey));
-    BIO_flush(bio);
+    (void) BIO_flush(bio);
     BIO_pop(b64);
     BIO_free(b64);
 
     get_user_info(info, sizeof(info));
     BIO_write(bfile, info, strlen(info));
-    BIO_flush(bfile);
+    (void) BIO_flush(bfile);
     BIO_free_all(bfile);
 
     return 1;
diff --git a/adb/adb_client.c b/adb/adb_client.c
index 586cd7b..1e47486 100644
--- a/adb/adb_client.c
+++ b/adb/adb_client.c
@@ -324,7 +324,10 @@
 
     buf[4] = 0;
     n = strtoul(buf, 0, 16);
-    if(n > 1024) goto oops;
+    if(n >= 0xffff) {
+        strcpy(__adb_error, "reply is too long (>= 64kB)");
+        goto oops;
+    }
 
     tmp = malloc(n + 1);
     if(tmp == 0) goto oops;
diff --git a/adb/backup_service.c b/adb/backup_service.c
index 669ff86..654e0f3 100644
--- a/adb/backup_service.c
+++ b/adb/backup_service.c
@@ -52,15 +52,12 @@
     pid_t pid;
     int s[2];
     char* operation;
-    int socketnum;
 
-    // Command string and choice of stdin/stdout for the pipe depend on our invocation
+    // Command string depends on our invocation
     if (op == BACKUP) {
         operation = "backup";
-        socketnum = STDOUT_FILENO;
     } else {
         operation = "restore";
-        socketnum = STDIN_FILENO;
     }
 
     D("backup_service(%s, %s)\n", operation, args);
diff --git a/adb/commandline.c b/adb/commandline.c
index 61167b2..2e4cd37 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -107,8 +107,12 @@
         "                                 will disconnect from all connected TCP/IP devices.\n"
         "\n"
         "device commands:\n"
-        "  adb push <local> <remote>    - copy file/dir to device\n"
-        "  adb pull <remote> [<local>]  - copy file/dir from device\n"
+        "  adb push [-p] <local> <remote>\n"
+        "                               - copy file/dir to device\n"
+        "                                 ('-p' to display the transfer progress)\n"
+        "  adb pull [-p] <remote> [<local>]\n"
+        "                               - copy file/dir from device\n"
+        "                                 ('-p' to display the transfer progress)\n"
         "  adb sync [ <directory> ]     - copy host->device only if changed\n"
         "                                 (-l means list but don't copy)\n"
         "                                 (see 'adb help all')\n"
@@ -132,6 +136,19 @@
         "                                 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 reverse --list           - list all reverse socket connections from device\n"
+        "  adb reverse <remote> <local> - reverse socket connections\n"
+        "                                 reverse specs are one of:\n"
+        "                                   tcp:<port>\n"
+        "                                   localabstract:<unix domain socket name>\n"
+        "                                   localreserved:<unix domain socket name>\n"
+        "                                   localfilesystem:<unix domain socket name>\n"
+        "  adb reverse --norebind <remote> <local>\n"
+        "                               - same as 'adb reverse <remote> <local>' but fails\n"
+        "                                 if <remote> is already reversed.\n"
+        "  adb reverse --remove <remote>\n"
+        "                               - remove a specific reversed socket connection\n"
+        "  adb reverse --remove-all     - remove all reversed socket connections from device\n"
         "  adb jdwp                     - list PIDs of processes hosting a JDWP transport\n"
         "  adb install [-l] [-r] [-d] [-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"
@@ -403,7 +420,7 @@
     }
 
     int opt = CHUNK_SIZE;
-    opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt));
+    opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
 
     total = sz;
     ptr = data;
@@ -678,10 +695,10 @@
     return 0;
 }
 
-static int mkdirs(char *path)
+static int mkdirs(const char *path)
 {
     int ret;
-    char *x = path + 1;
+    char *x = (char *)path + 1;
 
     for(;;) {
         x = adb_dirstart(x);
@@ -724,7 +741,7 @@
     if (argc < 2) return usage();
 
     adb_unlink(filename);
-    mkdirs((char *)filename);
+    mkdirs(filename);
     outFd = adb_creat(filename, 0640);
     if (outFd < 0) {
         fprintf(stderr, "adb: unable to open file %s\n", filename);
@@ -922,6 +939,28 @@
     return path_buf;
 }
 
+
+static void parse_push_pull_args(char** arg, int narg, char const** path1, char const** path2,
+                                 int* show_progress) {
+    *show_progress = 0;
+
+    if ((narg > 0) && !strcmp(*arg, "-p")) {
+        *show_progress = 1;
+        ++arg;
+        --narg;
+    }
+
+    if (narg > 0) {
+        *path1 = *arg;
+        ++arg;
+        --narg;
+    }
+
+    if (narg > 0) {
+        *path2 = *arg;
+    }
+}
+
 int adb_commandline(int argc, char **argv)
 {
     char buf[4096];
@@ -1274,8 +1313,11 @@
         return 0;
     }
 
-    if(!strcmp(argv[0], "forward")) {
+    if(!strcmp(argv[0], "forward") ||
+       !strcmp(argv[0], "reverse"))
+    {
         char host_prefix[64];
+        char reverse = (char) !strcmp(argv[0], "reverse");
         char remove = 0;
         char remove_all = 0;
         char list = 0;
@@ -1304,15 +1346,19 @@
         }
 
         // 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");
+        if (reverse) {
+            snprintf(host_prefix, sizeof host_prefix, "reverse");
         } else {
-            snprintf(host_prefix, sizeof host_prefix, "host");
+            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
@@ -1369,18 +1415,29 @@
     }
 
     if(!strcmp(argv[0], "push")) {
-        if(argc != 3) return usage();
-        return do_sync_push(argv[1], argv[2], 0 /* no verify APK */);
+        int show_progress = 0;
+        const char* lpath = NULL, *rpath = NULL;
+
+        parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress);
+
+        if ((lpath != NULL) && (rpath != NULL)) {
+            return do_sync_push(lpath, rpath, 0 /* no verify APK */, show_progress);
+        }
+
+        return usage();
     }
 
     if(!strcmp(argv[0], "pull")) {
-        if (argc == 2) {
-            return do_sync_pull(argv[1], ".");
-        } else if (argc == 3) {
-            return do_sync_pull(argv[1], argv[2]);
-        } else {
-            return usage();
+        int show_progress = 0;
+        const char* rpath = NULL, *lpath = ".";
+
+        parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress);
+
+        if (rpath != NULL) {
+            return do_sync_pull(rpath, lpath, show_progress);
         }
+
+        return usage();
     }
 
     if(!strcmp(argv[0], "install")) {
@@ -1687,6 +1744,8 @@
         } else if (!strcmp(argv[i], "--key")) {
             verify_apk = 0;
             i++;
+        } else if (!strcmp(argv[i], "--abi")) {
+            i++;
         }
     }
 
@@ -1718,7 +1777,7 @@
         }
     }
 
-    err = do_sync_push(apk_file, apk_dest, verify_apk);
+    err = do_sync_push(apk_file, apk_dest, verify_apk, 0 /* no show progress */);
     if (err) {
         goto cleanup_apk;
     } else {
@@ -1726,7 +1785,8 @@
     }
 
     if (verification_file != NULL) {
-        err = do_sync_push(verification_file, verification_dest, 0 /* no verify APK */);
+        err = do_sync_push(verification_file, verification_dest, 0 /* no verify APK */,
+                           0 /* no show progress */);
         if (err) {
             goto cleanup_apk;
         } else {
diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c
index 9fec081..dc4e77f 100644
--- a/adb/file_sync_client.c
+++ b/adb/file_sync_client.c
@@ -62,6 +62,22 @@
             total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
 }
 
+static const char* transfer_progress_format = "\rTransferring: %llu/%llu (%d%%)";
+
+static void print_transfer_progress(unsigned long long bytes_current,
+                                    unsigned long long bytes_total) {
+    if (bytes_total == 0) return;
+
+    fprintf(stderr, transfer_progress_format, bytes_current, bytes_total,
+            (int) (bytes_current * 100 / bytes_total));
+
+    if (bytes_current == bytes_total) {
+        fputc('\n', stderr);
+    }
+
+    fflush(stderr);
+}
+
 void sync_quit(int fd)
 {
     syncmsg msg;
@@ -207,9 +223,10 @@
     return 0;
 }
 
-static int write_data_file(int fd, const char *path, syncsendbuf *sbuf)
+static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, int show_progress)
 {
     int lfd, err = 0;
+    unsigned long long size = 0;
 
     lfd = adb_open(path, O_RDONLY);
     if(lfd < 0) {
@@ -217,6 +234,17 @@
         return -1;
     }
 
+    if (show_progress) {
+        // Determine local file size.
+        struct stat st;
+        if (lstat(path, &st)) {
+            fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno));
+            return -1;
+        }
+
+        size = st.st_size;
+    }
+
     sbuf->id = ID_DATA;
     for(;;) {
         int ret;
@@ -238,13 +266,18 @@
             break;
         }
         total_bytes += ret;
+
+        if (show_progress) {
+            print_transfer_progress(total_bytes, size);
+        }
     }
 
     adb_close(lfd);
     return err;
 }
 
-static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf)
+static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf,
+                             int show_progress)
 {
     int err = 0;
     int total = 0;
@@ -264,6 +297,10 @@
         }
         total += count;
         total_bytes += count;
+
+        if (show_progress) {
+            print_transfer_progress(total, size);
+        }
     }
 
     return err;
@@ -295,7 +332,7 @@
 #endif
 
 static int sync_send(int fd, const char *lpath, const char *rpath,
-                     unsigned mtime, mode_t mode, int verifyApk)
+                     unsigned mtime, mode_t mode, int verifyApk, int show_progress)
 {
     syncmsg msg;
     int len, r;
@@ -377,10 +414,10 @@
     }
 
     if (file_buffer) {
-        write_data_buffer(fd, file_buffer, size, sbuf);
+        write_data_buffer(fd, file_buffer, size, sbuf, show_progress);
         free(file_buffer);
     } else if (S_ISREG(mode))
-        write_data_file(fd, lpath, sbuf);
+        write_data_file(fd, lpath, sbuf, show_progress);
 #ifdef HAVE_SYMLINKS
     else if (S_ISLNK(mode))
         write_data_link(fd, lpath, sbuf);
@@ -419,10 +456,10 @@
     return -1;
 }
 
-static int mkdirs(char *name)
+static int mkdirs(const char *name)
 {
     int ret;
-    char *x = name + 1;
+    char *x = (char *)name + 1;
 
     for(;;) {
         x = adb_dirstart(x);
@@ -438,17 +475,38 @@
     return 0;
 }
 
-int sync_recv(int fd, const char *rpath, const char *lpath)
+int sync_recv(int fd, const char *rpath, const char *lpath, int show_progress)
 {
     syncmsg msg;
     int len;
     int lfd = -1;
     char *buffer = send_buffer.data;
     unsigned id;
+    unsigned long long size = 0;
 
     len = strlen(rpath);
     if(len > 1024) return -1;
 
+    if (show_progress) {
+        // Determine remote file size.
+        syncmsg stat_msg;
+        stat_msg.req.id = ID_STAT;
+        stat_msg.req.namelen = htoll(len);
+
+        if (writex(fd, &stat_msg.req, sizeof(stat_msg.req)) ||
+            writex(fd, rpath, len)) {
+            return -1;
+        }
+
+        if (readx(fd, &stat_msg.stat, sizeof(stat_msg.stat))) {
+            return -1;
+        }
+
+        if (stat_msg.stat.id != ID_STAT) return -1;
+
+        size = ltohl(stat_msg.stat.size);
+    }
+
     msg.req.id = ID_RECV;
     msg.req.namelen = htoll(len);
     if(writex(fd, &msg.req, sizeof(msg.req)) ||
@@ -463,7 +521,7 @@
 
     if((id == ID_DATA) || (id == ID_DONE)) {
         adb_unlink(lpath);
-        mkdirs((char *)lpath);
+        mkdirs(lpath);
         lfd = adb_creat(lpath, 0644);
         if(lfd < 0) {
             fprintf(stderr,"cannot create '%s': %s\n", lpath, strerror(errno));
@@ -502,6 +560,10 @@
         }
 
         total_bytes += len;
+
+        if (show_progress) {
+            print_transfer_progress(total_bytes, size);
+        }
     }
 
     adb_close(lfd);
@@ -721,7 +783,8 @@
         if(ci->flag == 0) {
             fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst);
             if(!listonly &&
-               sync_send(fd, ci->src, ci->dst, ci->time, ci->mode, 0 /* no verify APK */)){
+               sync_send(fd, ci->src, ci->dst, ci->time, ci->mode, 0 /* no verify APK */,
+                         0 /* no show progress */)) {
                 return 1;
             }
             pushed++;
@@ -739,7 +802,7 @@
 }
 
 
-int do_sync_push(const char *lpath, const char *rpath, int verifyApk)
+int do_sync_push(const char *lpath, const char *rpath, int verifyApk, int show_progress)
 {
     struct stat st;
     unsigned mode;
@@ -786,7 +849,7 @@
             rpath = tmp;
         }
         BEGIN();
-        if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, verifyApk)) {
+        if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, verifyApk, show_progress)) {
             return 1;
         } else {
             END();
@@ -923,7 +986,7 @@
         next = ci->next;
         if (ci->flag == 0) {
             fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
-            if (sync_recv(fd, ci->src, ci->dst)) {
+            if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) {
                 return 1;
             }
             pulled++;
@@ -940,7 +1003,7 @@
     return 0;
 }
 
-int do_sync_pull(const char *rpath, const char *lpath)
+int do_sync_pull(const char *rpath, const char *lpath, int show_progress)
 {
     unsigned mode;
     struct stat st;
@@ -981,7 +1044,7 @@
             }
         }
         BEGIN();
-        if(sync_recv(fd, rpath, lpath)) {
+        if (sync_recv(fd, rpath, lpath, show_progress)) {
             return 1;
         } else {
             END();
diff --git a/adb/file_sync_service.c b/adb/file_sync_service.c
index 577fb8f..1d80d26 100644
--- a/adb/file_sync_service.c
+++ b/adb/file_sync_service.c
@@ -68,7 +68,7 @@
                 *x = '/';
                 return ret;
             }
-            selinux_android_restorecon(name);
+            selinux_android_restorecon(name, 0);
         }
         *x++ = '/';
     }
@@ -172,7 +172,7 @@
 }
 
 static int handle_send_file(int s, char *path, uid_t uid,
-        gid_t gid, mode_t mode, char *buffer)
+        gid_t gid, mode_t mode, char *buffer, bool do_unlink)
 {
     syncmsg msg;
     unsigned int timestamp = 0;
@@ -236,7 +236,7 @@
         if(writex(fd, buffer, len)) {
             int saved_errno = errno;
             adb_close(fd);
-            adb_unlink(path);
+            if (do_unlink) adb_unlink(path);
             fd = -1;
             errno = saved_errno;
             if(fail_errno(s)) return -1;
@@ -246,7 +246,7 @@
     if(fd >= 0) {
         struct utimbuf u;
         adb_close(fd);
-        selinux_android_restorecon(path);
+        selinux_android_restorecon(path, 0);
         u.actime = timestamp;
         u.modtime = timestamp;
         utime(path, &u);
@@ -261,7 +261,7 @@
 fail:
     if(fd >= 0)
         adb_close(fd);
-    adb_unlink(path);
+    if (do_unlink) adb_unlink(path);
     return -1;
 }
 
@@ -323,6 +323,7 @@
     char *tmp;
     unsigned int mode;
     int is_link, ret;
+    bool do_unlink;
 
     tmp = strrchr(path,',');
     if(tmp) {
@@ -339,11 +340,16 @@
     if(!tmp || errno) {
         mode = 0644;
         is_link = 0;
+        do_unlink = true;
+    } else {
+        struct stat st;
+        /* Don't delete files before copying if they are not "regular" */
+        do_unlink = lstat(path, &st) || S_ISREG(st.st_mode) || S_ISLNK(st.st_mode);
+        if (do_unlink) {
+            adb_unlink(path);
+        }
     }
 
-    adb_unlink(path);
-
-
 #ifdef HAVE_SYMLINKS
     if(is_link)
         ret = handle_send_link(s, path, buffer);
@@ -366,7 +372,7 @@
         if (is_on_system(path)) {
             fs_config(tmp, 0, &uid, &gid, &mode, &cap);
         }
-        ret = handle_send_file(s, path, uid, gid, mode, buffer);
+        ret = handle_send_file(s, path, uid, gid, mode, buffer, do_unlink);
     }
 
     return ret;
diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h
index e402e06..3e7e096 100644
--- a/adb/file_sync_service.h
+++ b/adb/file_sync_service.h
@@ -72,15 +72,15 @@
     struct {
         unsigned id;
         unsigned msglen;
-    } status;    
+    } status;
 } syncmsg;
 
 
 void file_sync_service(int fd, void *cookie);
 int do_sync_ls(const char *path);
-int do_sync_push(const char *lpath, const char *rpath, int verifyApk);
+int do_sync_push(const char *lpath, const char *rpath, int verifyApk, int show_progress);
 int do_sync_sync(const char *lpath, const char *rpath, int listonly);
-int do_sync_pull(const char *rpath, const char *lpath);
+int do_sync_pull(const char *rpath, const char *lpath, int show_progress);
 
 #define SYNC_DATA_MAX (64*1024)
 
diff --git a/adb/framebuffer_service.c b/adb/framebuffer_service.c
index fa7fd98..8cbe840 100644
--- a/adb/framebuffer_service.c
+++ b/adb/framebuffer_service.c
@@ -61,7 +61,7 @@
     int w, h, f;
     int fds[2];
 
-    if (pipe(fds) < 0) goto pipefail;
+    if (pipe2(fds, O_CLOEXEC) < 0) goto pipefail;
 
     pid_t pid = fork();
     if (pid < 0) goto done;
diff --git a/adb/remount_service.c b/adb/remount_service.c
index ad61284..d3a649b 100644
--- a/adb/remount_service.c
+++ b/adb/remount_service.c
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/mount.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <unistd.h>
 
 #include "sysdeps.h"
 
@@ -35,7 +35,6 @@
 {
     int fd;
     int res;
-    int size;
     char *token = NULL;
     const char delims[] = "\n";
     char buf[4096];
@@ -45,7 +44,7 @@
         return NULL;
 
     buf[sizeof(buf) - 1] = '\0';
-    size = adb_read(fd, buf, sizeof(buf) - 1);
+    adb_read(fd, buf, sizeof(buf) - 1);
     adb_close(fd);
 
     token = strtok(buf, delims);
diff --git a/adb/services.c b/adb/services.c
index dcaf276..7b809da 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -141,6 +141,17 @@
     adb_close(fd);
 }
 
+void reverse_service(int fd, void* arg)
+{
+    const char* command = arg;
+
+    if (handle_forward_request(command, kTransportAny, NULL, fd) < 0) {
+        sendfailmsg(fd, "not a reverse forwarding command");
+    }
+    free(arg);
+    adb_close(fd);
+}
+
 #endif
 
 static int create_service_thread(void (*func)(int, void *), void *cookie)
@@ -385,6 +396,16 @@
         ret = create_service_thread(restart_tcp_service, (void *) (uintptr_t) port);
     } else if(!strncmp(name, "usb:", 4)) {
         ret = create_service_thread(restart_usb_service, NULL);
+    } else if (!strncmp(name, "reverse:", 8)) {
+        char* cookie = strdup(name + 8);
+        if (cookie == NULL) {
+            ret = -1;
+        } else {
+            ret = create_service_thread(reverse_service, cookie);
+            if (ret < 0) {
+                free(cookie);
+            }
+        }
 #endif
     }
     if (ret >= 0) {
@@ -447,7 +468,7 @@
 
     snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port);
 
-    fd = socket_network_client(hostbuf, port, SOCK_STREAM);
+    fd = socket_network_client_timeout(hostbuf, port, SOCK_STREAM, 10);
     if (fd < 0) {
         snprintf(buffer, buffer_size, "unable to connect to %s:%d", host, port);
         return;
diff --git a/adb/sockets.c b/adb/sockets.c
index de14a22..faa9564 100644
--- a/adb/sockets.c
+++ b/adb/sockets.c
@@ -23,6 +23,10 @@
 
 #include "sysdeps.h"
 
+#if !ADB_HOST
+#include <cutils/properties.h>
+#endif
+
 #define  TRACE_TAG  TRACE_SOCKETS
 #include "adb.h"
 
@@ -428,6 +432,9 @@
 {
     asocket *s;
     int fd;
+#if !ADB_HOST
+    char debug[PROPERTY_VALUE_MAX];
+#endif
 
 #if !ADB_HOST
     if (!strcmp(name,"jdwp")) {
@@ -444,7 +451,11 @@
     D("LS(%d): bound to '%s' via %d\n", s->id, name, fd);
 
 #if !ADB_HOST
-    if ((!strncmp(name, "root:", 5) && getuid() != 0)
+    if (!strncmp(name, "root:", 5))
+        property_get("ro.debuggable", debug, "");
+
+    if ((!strncmp(name, "root:", 5) && getuid() != 0
+        && strcmp(debug, "1") == 0)
         || !strncmp(name, "usb:", 4)
         || !strncmp(name, "tcpip:", 6)) {
         D("LS(%d): enabling exit_on_close\n", s->id);
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 4033b72..ba4306f 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -169,6 +169,8 @@
 /* normally provided by <cutils/sockets.h> */
 extern int socket_loopback_client(int port, int type);
 extern int socket_network_client(const char *host, int port, int type);
+extern int socket_network_client_timeout(const char *host, int port, int type,
+                                         int timeout);
 extern int socket_loopback_server(int port, int type);
 extern int socket_inaddr_any_server(int port, int type);
 
diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.c
index 2105b16..29f58ec 100644
--- a/adb/sysdeps_win32.c
+++ b/adb/sysdeps_win32.c
@@ -701,6 +701,13 @@
 }
 
 
+int socket_network_client_timeout(const char *host, int port, int type, int timeout)
+{
+    // TODO: implement timeouts for Windows.
+    return socket_network_client(host, port, type);
+}
+
+
 int socket_inaddr_any_server(int port, int type)
 {
     FH  f = _fh_alloc( &_fh_socket_class );
@@ -956,7 +963,7 @@
             avail = len;
 
         memcpy( bip->buff + bip->a_end, src, avail );
-        src   += avail;
+        src   = (const char *)src + avail;
         count += avail;
         len   -= avail;
 
@@ -1049,7 +1056,7 @@
         avail = len;
 
     memcpy( dst, bip->buff + bip->a_start, avail );
-    dst   += avail;
+    dst   = (char *)dst + avail;
     count += avail;
     len   -= avail;
 
diff --git a/adb/transport.c b/adb/transport.c
index 6002530..f35880c 100644
--- a/adb/transport.c
+++ b/adb/transport.c
@@ -1188,6 +1188,10 @@
                 D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno));
                 if (errno == EINTR)
                     continue;
+                if (errno == EAGAIN) {
+                    adb_sleep_ms(1); // just yield some cpu time
+                    continue;
+                }
             } else {
                 D("writex: fd=%d disconnected\n", fd);
             }
diff --git a/adb/transport_local.c b/adb/transport_local.c
index d2dbca6..948cc15 100644
--- a/adb/transport_local.c
+++ b/adb/transport_local.c
@@ -48,7 +48,7 @@
  * local transport it is connected. The list is used to detect when we're
  * trying to connect twice to a given local transport.
  */
-#define  ADB_LOCAL_TRANSPORT_MAX  16
+#define  ADB_LOCAL_TRANSPORT_MAX  64
 
 ADB_MUTEX_DEFINE( local_transports_lock );
 
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index cd5885e..957e5db 100755
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -51,7 +51,9 @@
 // BYD's USB Vendor ID
 #define VENDOR_ID_BYD           0x1D91
 // Compal's USB Vendor ID
-#define VENDOR_ID_COMPAL        0x1219
+#define VENDOR_ID_COMPAL        0x04B7
+// Compalcomm's USB Vendor ID
+#define VENDOR_ID_COMPALCOMM    0x1219
 // Dell's USB Vendor ID
 #define VENDOR_ID_DELL          0x413c
 // ECS's USB Vendor ID
@@ -72,6 +74,8 @@
 #define VENDOR_ID_GIGABYTE      0x0414
 // Gigaset's USB Vendor ID
 #define VENDOR_ID_GIGASET       0x1E85
+// GIONEE's USB Vendor ID
+#define VENDOR_ID_GIONEE        0x271D
 // Google's USB Vendor ID
 #define VENDOR_ID_GOOGLE        0x18d1
 // Haier's USB Vendor ID
@@ -80,6 +84,8 @@
 #define VENDOR_ID_HARRIS        0x19A5
 // Hisense's USB Vendor ID
 #define VENDOR_ID_HISENSE       0x109b
+// Honeywell's USB Vendor ID
+#define VENDOR_ID_HONEYWELL     0x0c2e
 // HP's USB Vendor ID
 #define VENDOR_ID_HP            0x03f0
 // HTC's USB Vendor ID
@@ -90,6 +96,8 @@
 #define VENDOR_ID_INQ_MOBILE    0x2314
 // Intel's USB Vendor ID
 #define VENDOR_ID_INTEL         0x8087
+// Intermec's USB Vendor ID
+#define VENDOR_ID_INTERMEC      0x067e
 // IRiver's USB Vendor ID
 #define VENDOR_ID_IRIVER        0x2420
 // K-Touch's USB Vendor ID
@@ -138,6 +146,8 @@
 #define VENDOR_ID_PMC           0x04DA
 // Positivo's USB Vendor ID
 #define VENDOR_ID_POSITIVO      0x1662
+// Prestigio's USB Vendor ID
+#define VENDOR_ID_PRESTIGIO     0x29e4
 // Qisda's USB Vendor ID
 #define VENDOR_ID_QISDA         0x1D45
 // Qualcomm's USB Vendor ID
@@ -152,6 +162,8 @@
 #define VENDOR_ID_SHARP         0x04dd
 // SK Telesys's USB Vendor ID
 #define VENDOR_ID_SK_TELESYS    0x1F53
+// Smartisan's USB Vendor ID
+#define VENDOR_ID_SMARTISAN     0x29a9
 // Sony's USB Vendor ID
 #define VENDOR_ID_SONY          0x054C
 // Sony Ericsson's USB Vendor ID
@@ -166,6 +178,8 @@
 #define VENDOR_ID_TI            0x0451
 // Toshiba's USB Vendor ID
 #define VENDOR_ID_TOSHIBA       0x0930
+// Unowhy's USB Vendor ID
+#define VENDOR_ID_UNOWHY        0x2A49
 // Vizio's USB Vendor ID
 #define VENDOR_ID_VIZIO         0xE040
 // Wacom's USB Vendor ID
@@ -191,6 +205,7 @@
     VENDOR_ID_ASUS,
     VENDOR_ID_BYD,
     VENDOR_ID_COMPAL,
+    VENDOR_ID_COMPALCOMM,
     VENDOR_ID_DELL,
     VENDOR_ID_ECS,
     VENDOR_ID_EMERGING_TECH,
@@ -201,15 +216,18 @@
     VENDOR_ID_GARMIN_ASUS,
     VENDOR_ID_GIGABYTE,
     VENDOR_ID_GIGASET,
+    VENDOR_ID_GIONEE,
     VENDOR_ID_GOOGLE,
     VENDOR_ID_HAIER,
     VENDOR_ID_HARRIS,
     VENDOR_ID_HISENSE,
+    VENDOR_ID_HONEYWELL,
     VENDOR_ID_HP,
     VENDOR_ID_HTC,
     VENDOR_ID_HUAWEI,
     VENDOR_ID_INQ_MOBILE,
     VENDOR_ID_INTEL,
+    VENDOR_ID_INTERMEC,
     VENDOR_ID_IRIVER,
     VENDOR_ID_KOBO,
     VENDOR_ID_K_TOUCH,
@@ -234,6 +252,7 @@
     VENDOR_ID_PHILIPS,
     VENDOR_ID_PMC,
     VENDOR_ID_POSITIVO,
+    VENDOR_ID_PRESTIGIO,
     VENDOR_ID_QISDA,
     VENDOR_ID_QUALCOMM,
     VENDOR_ID_QUANTA,
@@ -241,6 +260,7 @@
     VENDOR_ID_SAMSUNG,
     VENDOR_ID_SHARP,
     VENDOR_ID_SK_TELESYS,
+    VENDOR_ID_SMARTISAN,
     VENDOR_ID_SONY,
     VENDOR_ID_SONY_ERICSSON,
     VENDOR_ID_T_AND_A,
@@ -248,6 +268,7 @@
     VENDOR_ID_TELEEPOCH,
     VENDOR_ID_TI,
     VENDOR_ID_TOSHIBA,
+    VENDOR_ID_UNOWHY,
     VENDOR_ID_VIZIO,
     VENDOR_ID_WACOM,
     VENDOR_ID_XIAOMI,
diff --git a/adb/usb_windows.c b/adb/usb_windows.c
index 4936b77..1309a78 100644
--- a/adb/usb_windows.c
+++ b/adb/usb_windows.c
@@ -310,14 +310,14 @@
       int xfer = (len > 4096) ? 4096 : len;
 
       ret = AdbReadEndpointSync(handle->adb_read_pipe,
-                                  (void*)data,
+                                  data,
                                   (unsigned long)xfer,
                                   &read,
                                   time_out);
       int saved_errno = GetLastError();
       D("usb_write got: %ld, expected: %d, errno: %d\n", read, xfer, saved_errno);
       if (ret) {
-        data += read;
+        data = (char *)data + read;
         len -= read;
 
         if (len == 0)
diff --git a/adf/libadf/adf.c b/adf/libadf/adf.c
index 871629e..1d19152 100644
--- a/adf/libadf/adf.c
+++ b/adf/libadf/adf.c
@@ -768,7 +768,7 @@
         const __u32 *formats, size_t n_formats,
         adf_id_t *interface, adf_id_t *overlay_engine)
 {
-    adf_id_t *intfs;
+    adf_id_t *intfs = NULL;
     ssize_t n_intfs = adf_interfaces(dev, &intfs);
 
     if (n_intfs < 0)
diff --git a/adf/libadfhwc/adfhwc.cpp b/adf/libadfhwc/adfhwc.cpp
index dee3cae..57e09eb 100644
--- a/adf/libadfhwc/adfhwc.cpp
+++ b/adf/libadfhwc/adfhwc.cpp
@@ -257,7 +257,7 @@
 
         ret = adf_set_event(dup_intf_fd, ADF_EVENT_HOTPLUG, 1);
         if (ret < 0 && ret != -EINVAL) {
-            ALOGE("failed to enable hotplug event on display %u: %s",
+            ALOGE("failed to enable hotplug event on display %zu: %s",
                     i, strerror(errno));
             goto err;
         }
diff --git a/charger/Android.mk b/charger/Android.mk
index b9d3473..40c7d78 100644
--- a/charger/Android.mk
+++ b/charger/Android.mk
@@ -24,7 +24,7 @@
 
 LOCAL_C_INCLUDES := bootable/recovery
 
-LOCAL_STATIC_LIBRARIES := libminui libpixelflinger_static libpng
+LOCAL_STATIC_LIBRARIES := libminui libpng
 ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
 LOCAL_STATIC_LIBRARIES += libsuspend
 endif
diff --git a/charger/charger.c b/charger/charger.c
index 66ddeaf..15add87 100644
--- a/charger/charger.c
+++ b/charger/charger.c
@@ -40,6 +40,7 @@
 #include <cutils/list.h>
 #include <cutils/misc.h>
 #include <cutils/uevent.h>
+#include <cutils/properties.h>
 
 #ifdef CHARGER_ENABLE_SUSPEND
 #include <suspend/autosuspend.h>
@@ -47,6 +48,8 @@
 
 #include "minui/minui.h"
 
+char *locale;
+
 #ifndef max
 #define max(a,b) ((a) > (b) ? (a) : (b))
 #endif
@@ -89,7 +92,6 @@
 };
 
 struct frame {
-    const char *name;
     int disp_time;
     int min_capacity;
     bool level_only;
@@ -140,33 +142,27 @@
 
 static struct frame batt_anim_frames[] = {
     {
-        .name = "charger/battery_0",
         .disp_time = 750,
         .min_capacity = 0,
     },
     {
-        .name = "charger/battery_1",
         .disp_time = 750,
         .min_capacity = 20,
     },
     {
-        .name = "charger/battery_2",
         .disp_time = 750,
         .min_capacity = 40,
     },
     {
-        .name = "charger/battery_3",
         .disp_time = 750,
         .min_capacity = 60,
     },
     {
-        .name = "charger/battery_4",
         .disp_time = 750,
         .min_capacity = 80,
         .level_only = true,
     },
     {
-        .name = "charger/battery_5",
         .disp_time = 750,
         .min_capacity = BATTERY_FULL_THRESH,
     },
@@ -196,8 +192,8 @@
 static void clear_screen(void)
 {
     gr_color(0, 0, 0, 255);
-    gr_fill(0, 0, gr_fb_width(), gr_fb_height());
-};
+    gr_clear();
+}
 
 #define MAX_KLOG_WRITE_BUF_SZ 256
 
@@ -657,8 +653,8 @@
 
     if (batt_anim->num_frames != 0) {
         draw_surface_centered(charger, frame->surface);
-        LOGV("drawing frame #%d name=%s min_cap=%d time=%d\n",
-             batt_anim->cur_frame, frame->name, frame->min_capacity,
+        LOGV("drawing frame #%d min_cap=%d time=%d\n",
+             batt_anim->cur_frame, frame->min_capacity,
              frame->disp_time);
     }
 }
@@ -835,8 +831,16 @@
         if (key->down) {
             int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME;
             if (now >= reboot_timeout) {
-                LOGI("[%lld] rebooting\n", now);
-                android_reboot(ANDROID_RB_RESTART, 0, 0);
+                /* We do not currently support booting from charger mode on
+                   all devices. Check the property and continue booting or reboot
+                   accordingly. */
+                if (property_get_bool("ro.enable_boot_charger_mode", false)) {
+                    LOGI("[%lld] booting from charger mode\n", now);
+                    property_set("sys.boot_from_charger_mode", "1");
+                } else {
+                    LOGI("[%lld] rebooting\n", now);
+                    android_reboot(ANDROID_RB_RESTART, 0, 0);
+                }
             } else {
                 /* if the key is pressed but timeout hasn't expired,
                  * make sure we wake up at the right-ish time to check
@@ -978,22 +982,29 @@
     charger->uevent_fd = fd;
     coldboot(charger, "/sys/class/power_supply", "add");
 
-    ret = res_create_surface("charger/battery_fail", &charger->surf_unknown);
+    ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);
     if (ret < 0) {
-        LOGE("Cannot load image\n");
+        LOGE("Cannot load battery_fail image\n");
         charger->surf_unknown = NULL;
     }
 
-    for (i = 0; i < charger->batt_anim->num_frames; i++) {
-        struct frame *frame = &charger->batt_anim->frames[i];
+    charger->batt_anim = &battery_animation;
 
-        ret = res_create_surface(frame->name, &frame->surface);
-        if (ret < 0) {
-            LOGE("Cannot load image %s\n", frame->name);
-            /* TODO: free the already allocated surfaces... */
-            charger->batt_anim->num_frames = 0;
-            charger->batt_anim->num_cycles = 1;
-            break;
+    gr_surface* scale_frames;
+    int scale_count;
+    ret = res_create_multi_display_surface("charger/battery_scale", &scale_count, &scale_frames);
+    if (ret < 0) {
+        LOGE("Cannot load battery_scale image\n");
+        charger->batt_anim->num_frames = 0;
+        charger->batt_anim->num_cycles = 1;
+    } else if (scale_count != charger->batt_anim->num_frames) {
+        LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n",
+             scale_count, charger->batt_anim->num_frames);
+        charger->batt_anim->num_frames = 0;
+        charger->batt_anim->num_cycles = 1;
+    } else {
+        for (i = 0; i < charger->batt_anim->num_frames; i++) {
+            charger->batt_anim->frames[i].surface = scale_frames[i];
         }
     }
 
diff --git a/charger/images/battery_0.png b/charger/images/battery_0.png
deleted file mode 100644
index 2347074..0000000
--- a/charger/images/battery_0.png
+++ /dev/null
Binary files differ
diff --git a/charger/images/battery_1.png b/charger/images/battery_1.png
deleted file mode 100644
index cd34620..0000000
--- a/charger/images/battery_1.png
+++ /dev/null
Binary files differ
diff --git a/charger/images/battery_2.png b/charger/images/battery_2.png
deleted file mode 100644
index 3e4095e..0000000
--- a/charger/images/battery_2.png
+++ /dev/null
Binary files differ
diff --git a/charger/images/battery_3.png b/charger/images/battery_3.png
deleted file mode 100644
index 08c1551..0000000
--- a/charger/images/battery_3.png
+++ /dev/null
Binary files differ
diff --git a/charger/images/battery_4.png b/charger/images/battery_4.png
deleted file mode 100644
index 3a678da..0000000
--- a/charger/images/battery_4.png
+++ /dev/null
Binary files differ
diff --git a/charger/images/battery_5.png b/charger/images/battery_5.png
deleted file mode 100644
index d8dc40e..0000000
--- a/charger/images/battery_5.png
+++ /dev/null
Binary files differ
diff --git a/charger/images/battery_charge.png b/charger/images/battery_charge.png
deleted file mode 100644
index b501933..0000000
--- a/charger/images/battery_charge.png
+++ /dev/null
Binary files differ
diff --git a/charger/images/battery_fail.png b/charger/images/battery_fail.png
index 36fc254..aded88a 100644
--- a/charger/images/battery_fail.png
+++ b/charger/images/battery_fail.png
Binary files differ
diff --git a/charger/images/battery_scale.png b/charger/images/battery_scale.png
new file mode 100644
index 0000000..2ae8f0f
--- /dev/null
+++ b/charger/images/battery_scale.png
Binary files differ
diff --git a/cpio/Android.mk b/cpio/Android.mk
index 5184463..575beb2 100644
--- a/cpio/Android.mk
+++ b/cpio/Android.mk
@@ -8,6 +8,8 @@
 
 LOCAL_MODULE := mkbootfs
 
+LOCAL_CFLAGS := -Werror
+
 include $(BUILD_HOST_EXECUTABLE)
 
 $(call dist-for-goals,dist_files,$(LOCAL_BUILT_MODULE))
diff --git a/cpio/mkbootfs.c b/cpio/mkbootfs.c
index 7d3740c..7175749 100644
--- a/cpio/mkbootfs.c
+++ b/cpio/mkbootfs.c
@@ -78,8 +78,9 @@
         s->st_mode = empty_path_config->mode | (s->st_mode & ~07777);
     } 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, &capabilities);
+        unsigned st_mode = s->st_mode;
+        fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &st_mode, &capabilities);
+        s->st_mode = (typeof(s->st_mode)) st_mode;
     }
 }
 
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 422a86a..c33b263 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -1,70 +1,67 @@
-# Copyright 2005 The Android Open Source Project
-
-ifneq ($(filter arm mips x86,$(TARGET_ARCH)),)
-
 LOCAL_PATH:= $(call my-dir)
+
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	backtrace.cpp \
-	debuggerd.cpp \
-	getevent.cpp \
-	tombstone.cpp \
-	utility.cpp \
-	$(TARGET_ARCH)/machine.cpp \
+    backtrace.cpp \
+    debuggerd.cpp \
+    getevent.cpp \
+    tombstone.cpp \
+    utility.cpp \
 
-LOCAL_CONLYFLAGS := -std=gnu99
-LOCAL_CPPFLAGS := -std=gnu++11
-LOCAL_CFLAGS := \
-	-Wall \
-	-Wno-array-bounds \
-	-Werror \
+LOCAL_SRC_FILES_arm    := arm/machine.cpp
+LOCAL_SRC_FILES_arm64  := arm64/machine.cpp
+LOCAL_SRC_FILES_mips   := mips/machine.cpp
+LOCAL_SRC_FILES_mips64 := mips/machine.cpp
+LOCAL_SRC_FILES_x86    := x86/machine.cpp
+LOCAL_SRC_FILES_x86_64 := x86_64/machine.cpp
 
-LOCAL_MODULE := debuggerd
-
-ifeq ($(ARCH_ARM_HAVE_VFP),true)
-LOCAL_CFLAGS += -DWITH_VFP
-endif # ARCH_ARM_HAVE_VFP
-ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
-LOCAL_CFLAGS += -DWITH_VFP_D32
-endif # ARCH_ARM_HAVE_VFP_D32
+LOCAL_CPPFLAGS := \
+    -std=gnu++11 \
+    -W -Wall -Wextra \
+    -Wunused \
+    -Werror \
 
 LOCAL_SHARED_LIBRARIES := \
-	libbacktrace \
-	libc \
-	libcutils \
-	liblog \
-	libselinux \
+    libbacktrace \
+    libcutils \
+    liblog \
+    libselinux \
 
 include external/stlport/libstlport.mk
 
+LOCAL_MODULE := debuggerd
+LOCAL_MODULE_STEM_32 := debuggerd
+LOCAL_MODULE_STEM_64 := debuggerd64
+LOCAL_MULTILIB := both
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+
 include $(BUILD_EXECUTABLE)
 
+
+
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := crasher.c
-LOCAL_SRC_FILES += $(TARGET_ARCH)/crashglue.S
-LOCAL_MODULE := crasher
+LOCAL_SRC_FILES_arm    := arm/crashglue.S
+LOCAL_SRC_FILES_arm64  := arm64/crashglue.S
+LOCAL_SRC_FILES_mips   := mips/crashglue.S
+LOCAL_SRC_FILES_mips64 := mips/crashglue.S
+LOCAL_SRC_FILES_x86    := x86/crashglue.S
+LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS += -fstack-protector-all -Wno-unused-parameter -Wno-free-nonheap-object
+LOCAL_CFLAGS += -fstack-protector-all -Werror -Wno-free-nonheap-object
 #LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_SHARED_LIBRARIES := libcutils liblog libc
-include $(BUILD_EXECUTABLE)
 
-ifeq ($(ARCH_ARM_HAVE_VFP),true)
-include $(CLEAR_VARS)
-
-LOCAL_CFLAGS += -DWITH_VFP
+# The arm emulator has VFP but not VFPv3-D32.
 ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
-LOCAL_CFLAGS += -DWITH_VFP_D32
-endif # ARCH_ARM_HAVE_VFP_D32
+LOCAL_ASFLAGS_arm += -DHAS_VFP_D32
+endif
 
-LOCAL_SRC_FILES := vfp-crasher.c vfp.S
-LOCAL_MODULE := vfp-crasher
-LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-LOCAL_MODULE_TAGS := optional
-LOCAL_SHARED_LIBRARIES := libcutils liblog libc
+LOCAL_MODULE := crasher
+LOCAL_MODULE_STEM_32 := crasher
+LOCAL_MODULE_STEM_64 := crasher64
+LOCAL_MULTILIB := both
+
 include $(BUILD_EXECUTABLE)
-endif # ARCH_ARM_HAVE_VFP == true
-
-endif # arm or x86 in TARGET_ARCH
diff --git a/debuggerd/arm/crashglue.S b/debuggerd/arm/crashglue.S
index eb9d0e3..4fbfd6e 100644
--- a/debuggerd/arm/crashglue.S
+++ b/debuggerd/arm/crashglue.S
@@ -1,8 +1,5 @@
 .globl crash1
 .type crash1, %function
-.globl crashnostack
-.type crashnostack, %function
-
 crash1:
 	ldr r0, =0xa5a50000
 	ldr r1, =0xa5a50001
@@ -18,11 +15,48 @@
 	ldr r11, =0xa5a50011
 	ldr r12, =0xa5a50012
 
+
+	fconstd   d0, #0
+	fconstd   d1, #1
+	fconstd   d2, #2
+	fconstd   d3, #3
+	fconstd   d4, #4
+	fconstd   d5, #5
+	fconstd   d6, #6
+	fconstd   d7, #7
+	fconstd   d8, #8
+	fconstd   d9, #9
+	fconstd   d10, #10
+	fconstd   d11, #11
+	fconstd   d12, #12
+	fconstd   d13, #13
+	fconstd   d14, #14
+	fconstd   d15, #15
+#if defined(HAS_VFP_D32)
+	fconstd   d16, #16
+	fconstd   d17, #17
+	fconstd   d18, #18
+	fconstd   d19, #19
+	fconstd   d20, #20
+	fconstd   d21, #21
+	fconstd   d22, #22
+	fconstd   d23, #23
+	fconstd   d24, #24
+	fconstd   d25, #25
+	fconstd   d26, #26
+	fconstd   d27, #27
+	fconstd   d28, #28
+	fconstd   d29, #29
+	fconstd   d30, #30
+	fconstd   d31, #31
+#endif
+
 	mov lr, #0
 	ldr lr, [lr]
 	b .
 
-
+.globl crashnostack
+.type crashnostack, %function
 crashnostack:
 	mov sp, #0
 	mov r0, #0
diff --git a/debuggerd/arm/machine.cpp b/debuggerd/arm/machine.cpp
index 3fba6db..8270066 100644
--- a/debuggerd/arm/machine.cpp
+++ b/debuggerd/arm/machine.cpp
@@ -27,146 +27,68 @@
 #include "../utility.h"
 #include "../machine.h"
 
-// enable to dump memory pointed to by every register
-#define DUMP_MEMORY_FOR_ALL_REGISTERS 1
-
-#ifdef WITH_VFP
-#ifdef WITH_VFP_D32
-#define NUM_VFP_REGS 32
-#else
-#define NUM_VFP_REGS 16
-#endif
-#endif
-
-static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) {
-  char code_buffer[64];       // actual 8+1+((8+1)*4) + 1 == 45
-  char ascii_buffer[32];      // actual 16 + 1 == 17
-  uintptr_t p, end;
-
-  p = addr & ~3;
-  p -= 32;
-  if (p > addr) {
-    // catch underflow
-    p = 0;
-  }
-  // Dump more memory content for the crashing thread.
-  end = p + 256;
-  // catch overflow; 'end - p' has to be multiples of 16
-  while (end < p)
-    end -= 16;
-
-  // Dump the code around PC as:
-  //  addr     contents                             ascii
-  //  00008d34 ef000000 e8bd0090 e1b00000 512fff1e  ............../Q
-  //  00008d44 ea00b1f9 e92d0090 e3a070fc ef000000  ......-..p......
-  while (p < end) {
-    char* asc_out = ascii_buffer;
-
-    sprintf(code_buffer, "%08x ", p);
-
-    int i;
-    for (i = 0; i < 4; i++) {
-      // If we see (data == -1 && errno != 0), we know that the ptrace
-      // call failed, probably because we're dumping memory in an
-      // unmapped or inaccessible page.  I don't know if there's
-      // value in making that explicit in the output -- it likely
-      // just complicates parsing and clarifies nothing for the
-      // enlightened reader.
-      long data = ptrace(PTRACE_PEEKTEXT, tid, reinterpret_cast<void*>(p), NULL);
-      sprintf(code_buffer + strlen(code_buffer), "%08lx ", data);
-
-      // Enable the following code blob to dump ASCII values
-#if 0
-      int j;
-      for (j = 0; j < 4; j++) {
-        // Our isprint() allows high-ASCII characters that display
-        // differently (often badly) in different viewers, so we
-        // just use a simpler test.
-        char val = (data >> (j*8)) & 0xff;
-        if (val >= 0x20 && val < 0x7f) {
-          *asc_out++ = val;
-        } else {
-          *asc_out++ = '.';
-        }
-      }
-#endif
-      p += 4;
-    }
-    *asc_out = '\0';
-    _LOG(log, scope_flags, "    %s %s\n", code_buffer, ascii_buffer);
-  }
-}
-
-// If configured to do so, dump memory around *all* registers
-// for the crashing thread.
-void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
-  struct pt_regs regs;
+void dump_memory_and_code(log_t* log, pid_t tid) {
+  pt_regs regs;
   if (ptrace(PTRACE_GETREGS, tid, 0, &regs)) {
     return;
   }
 
-  if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) {
-    static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";
+  static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";
 
-    for (int reg = 0; reg < 14; reg++) {
-      // this may not be a valid way to access, but it'll do for now
-      uintptr_t addr = regs.uregs[reg];
+  for (int reg = 0; reg < 14; reg++) {
+    // this may not be a valid way to access, but it'll do for now
+    uintptr_t addr = regs.uregs[reg];
 
-      // Don't bother if it looks like a small int or ~= null, or if
-      // it's in the kernel area.
-      if (addr < 4096 || addr >= 0xc0000000) {
-        continue;
-      }
-
-      _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
-      dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE);
+    // Don't bother if it looks like a small int or ~= null, or if
+    // it's in the kernel area.
+    if (addr < 4096 || addr >= 0xc0000000) {
+      continue;
     }
+
+    _LOG(log, logtype::MEMORY, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
+    dump_memory(log, tid, addr);
   }
 
   // explicitly allow upload of code dump logging
-  _LOG(log, scope_flags, "\ncode around pc:\n");
-  dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_pc), scope_flags);
+  _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
+  dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_pc));
 
   if (regs.ARM_pc != regs.ARM_lr) {
-    _LOG(log, scope_flags, "\ncode around lr:\n");
-    dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_lr), scope_flags);
+    _LOG(log, logtype::MEMORY, "\ncode around lr:\n");
+    dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_lr));
   }
 }
 
-void dump_registers(log_t* log, pid_t tid, int scope_flags) {
-  struct pt_regs r;
+void dump_registers(log_t* log, pid_t tid) {
+  pt_regs r;
   if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
-    _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+    _LOG(log, logtype::REGISTERS, "cannot get registers: %s\n", strerror(errno));
     return;
   }
 
-  _LOG(log, scope_flags, "    r0 %08x  r1 %08x  r2 %08x  r3 %08x\n",
+  _LOG(log, logtype::REGISTERS, "    r0 %08x  r1 %08x  r2 %08x  r3 %08x\n",
        static_cast<uint32_t>(r.ARM_r0), static_cast<uint32_t>(r.ARM_r1),
        static_cast<uint32_t>(r.ARM_r2), static_cast<uint32_t>(r.ARM_r3));
-  _LOG(log, scope_flags, "    r4 %08x  r5 %08x  r6 %08x  r7 %08x\n",
+  _LOG(log, logtype::REGISTERS, "    r4 %08x  r5 %08x  r6 %08x  r7 %08x\n",
        static_cast<uint32_t>(r.ARM_r4), static_cast<uint32_t>(r.ARM_r5),
        static_cast<uint32_t>(r.ARM_r6), static_cast<uint32_t>(r.ARM_r7));
-  _LOG(log, scope_flags, "    r8 %08x  r9 %08x  sl %08x  fp %08x\n",
+  _LOG(log, logtype::REGISTERS, "    r8 %08x  r9 %08x  sl %08x  fp %08x\n",
        static_cast<uint32_t>(r.ARM_r8), static_cast<uint32_t>(r.ARM_r9),
        static_cast<uint32_t>(r.ARM_r10), static_cast<uint32_t>(r.ARM_fp));
-  _LOG(log, scope_flags, "    ip %08x  sp %08x  lr %08x  pc %08x  cpsr %08x\n",
+  _LOG(log, logtype::REGISTERS, "    ip %08x  sp %08x  lr %08x  pc %08x  cpsr %08x\n",
        static_cast<uint32_t>(r.ARM_ip), static_cast<uint32_t>(r.ARM_sp),
        static_cast<uint32_t>(r.ARM_lr), static_cast<uint32_t>(r.ARM_pc),
        static_cast<uint32_t>(r.ARM_cpsr));
 
-#ifdef WITH_VFP
-  struct user_vfp vfp_regs;
-  int i;
-
+  user_vfp vfp_regs;
   if (ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) {
-    _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+    _LOG(log, logtype::REGISTERS, "cannot get registers: %s\n", strerror(errno));
     return;
   }
 
-  for (i = 0; i < NUM_VFP_REGS; i += 2) {
-    _LOG(log, scope_flags, "    d%-2d %016llx  d%-2d %016llx\n",
+  for (size_t i = 0; i < 32; i += 2) {
+    _LOG(log, logtype::REGISTERS, "    d%-2d %016llx  d%-2d %016llx\n",
          i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]);
   }
-  _LOG(log, scope_flags, "    scr %08lx\n", vfp_regs.fpscr);
-#endif
+  _LOG(log, logtype::REGISTERS, "    scr %08lx\n", vfp_regs.fpscr);
 }
diff --git a/debuggerd/arm64/crashglue.S b/debuggerd/arm64/crashglue.S
new file mode 100644
index 0000000..e58b542
--- /dev/null
+++ b/debuggerd/arm64/crashglue.S
@@ -0,0 +1,79 @@
+.globl crash1
+.type crash1, %function
+crash1:
+	ldr x0, =0xa5a50000
+	ldr x1, =0xa5a50001
+	ldr x2, =0xa5a50002
+	ldr x3, =0xa5a50003
+	ldr x4, =0xa5a50004
+	ldr x5, =0xa5a50005
+	ldr x6, =0xa5a50006
+	ldr x7, =0xa5a50007
+	ldr x8, =0xa5a50008
+	ldr x9, =0xa5a50009
+	ldr x10, =0xa5a50010
+	ldr x11, =0xa5a50011
+	ldr x12, =0xa5a50012
+	ldr x13, =0xa5a50013
+	ldr x14, =0xa5a50014
+	ldr x15, =0xa5a50015
+	ldr x16, =0xa5a50016
+	ldr x17, =0xa5a50017
+	ldr x18, =0xa5a50018
+	ldr x19, =0xa5a50019
+	ldr x20, =0xa5a50020
+	ldr x21, =0xa5a50021
+	ldr x22, =0xa5a50022
+	ldr x23, =0xa5a50023
+	ldr x24, =0xa5a50024
+	ldr x25, =0xa5a50025
+	ldr x26, =0xa5a50026
+	ldr x27, =0xa5a50027
+	ldr x28, =0xa5a50028
+	ldr x29, =0xa5a50029
+
+	fmov   d0, -1.0  // -1 is more convincing than 0.
+	fmov   d1, 1.0
+	fmov   d2, 2.0
+	fmov   d3, 3.0
+	fmov   d4, 4.0
+	fmov   d5, 5.0
+	fmov   d6, 6.0
+	fmov   d7, 7.0
+	fmov   d8, 8.0
+	fmov   d9, 9.0
+	fmov   d10, 10.0
+	fmov   d11, 11.0
+	fmov   d12, 12.0
+	fmov   d13, 13.0
+	fmov   d14, 14.0
+	fmov   d15, 15.0
+	fmov   d16, 16.0
+	fmov   d17, 17.0
+	fmov   d18, 18.0
+	fmov   d19, 19.0
+	fmov   d20, 20.0
+	fmov   d21, 21.0
+	fmov   d22, 22.0
+	fmov   d23, 23.0
+	fmov   d24, 24.0
+	fmov   d25, 25.0
+	fmov   d26, 26.0
+	fmov   d27, 27.0
+	fmov   d28, 28.0
+	fmov   d29, 29.0
+	fmov   d30, 30.0
+	fmov   d31, 31.0
+
+	mov x30, xzr
+	ldr x30, [x30]
+	b .
+
+
+.globl crashnostack
+.type crashnostack, %function
+crashnostack:
+	mov x0, xzr
+	add sp, x0, xzr
+	ldr x0, [x0]
+	b .
diff --git a/debuggerd/arm64/machine.cpp b/debuggerd/arm64/machine.cpp
new file mode 100644
index 0000000..ec664bd
--- /dev/null
+++ b/debuggerd/arm64/machine.cpp
@@ -0,0 +1,112 @@
+/*
+ *
+ * Copyright 2014, 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 <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/user.h>
+#include <sys/uio.h>
+#include <linux/elf.h>
+
+#include "../utility.h"
+#include "../machine.h"
+
+void dump_memory_and_code(log_t* log, pid_t tid) {
+    struct user_pt_regs regs;
+    struct iovec io;
+    io.iov_base = &regs;
+    io.iov_len = sizeof(regs);
+
+    if (ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, &io) == -1) {
+        _LOG(log, logtype::ERROR, "%s: ptrace failed to get registers: %s\n",
+             __func__, strerror(errno));
+        return;
+    }
+
+    for (int reg = 0; reg < 31; reg++) {
+        uintptr_t addr = regs.regs[reg];
+
+        /*
+         * Don't bother if it looks like a small int or ~= null, or if
+         * it's in the kernel area.
+         */
+        if (addr < 4096 || addr >= (1UL<<63)) {
+            continue;
+        }
+
+        _LOG(log, logtype::MEMORY, "\nmemory near x%d:\n", reg);
+        dump_memory(log, tid, addr);
+    }
+
+    _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
+    dump_memory(log, tid, (uintptr_t)regs.pc);
+
+    if (regs.pc != regs.sp) {
+        _LOG(log, logtype::MEMORY, "\ncode around sp:\n");
+        dump_memory(log, tid, (uintptr_t)regs.sp);
+    }
+}
+
+void dump_registers(log_t* log, pid_t tid) {
+  struct user_pt_regs r;
+  struct iovec io;
+  io.iov_base = &r;
+  io.iov_len = sizeof(r);
+
+  if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRSTATUS, (void*) &io) == -1) {
+    _LOG(log, logtype::ERROR, "ptrace error: %s\n", strerror(errno));
+    return;
+  }
+
+  for (int i = 0; i < 28; i += 4) {
+    _LOG(log, logtype::REGISTERS,
+         "    x%-2d  %016lx  x%-2d  %016lx  x%-2d  %016lx  x%-2d  %016lx\n",
+         i, (uint64_t)r.regs[i],
+         i+1, (uint64_t)r.regs[i+1],
+         i+2, (uint64_t)r.regs[i+2],
+         i+3, (uint64_t)r.regs[i+3]);
+  }
+
+  _LOG(log, logtype::REGISTERS, "    x28  %016lx  x29  %016lx  x30  %016lx\n",
+       (uint64_t)r.regs[28], (uint64_t)r.regs[29], (uint64_t)r.regs[30]);
+
+  _LOG(log, logtype::REGISTERS, "    sp   %016lx  pc   %016lx\n",
+       (uint64_t)r.sp, (uint64_t)r.pc);
+
+
+  struct user_fpsimd_state f;
+  io.iov_base = &f;
+  io.iov_len = sizeof(f);
+
+  if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRFPREG, (void*) &io) == -1) {
+    _LOG(log, logtype::ERROR, "ptrace error: %s\n", strerror(errno));
+    return;
+  }
+
+  for (int i = 0; i < 32; i += 4) {
+    _LOG(log, logtype::REGISTERS, "    v%-2d  %016lx  v%-2d  %016lx  v%-2d  %016lx  v%-2d  %016lx\n",
+         i, (uint64_t)f.vregs[i],
+         i+1, (uint64_t)f.vregs[i+1],
+         i+2, (uint64_t)f.vregs[i+2],
+         i+3, (uint64_t)f.vregs[i+3]);
+  }
+}
diff --git a/debuggerd/backtrace.cpp b/debuggerd/backtrace.cpp
index d388348..c4a2143 100644
--- a/debuggerd/backtrace.cpp
+++ b/debuggerd/backtrace.cpp
@@ -30,6 +30,7 @@
 #include <UniquePtr.h>
 
 #include "backtrace.h"
+
 #include "utility.h"
 
 static void dump_process_header(log_t* log, pid_t pid) {
@@ -48,16 +49,17 @@
   struct tm tm;
   localtime_r(&t, &tm);
   char timestr[64];
+  _LOG(log, logtype::BACKTRACE, "\n\nABI: '%s'\n", ABI_STRING);
   strftime(timestr, sizeof(timestr), "%F %T", &tm);
-  _LOG(log, SCOPE_AT_FAULT, "\n\n----- pid %d at %s -----\n", pid, timestr);
+  _LOG(log, logtype::BACKTRACE, "\n----- pid %d at %s -----\n", pid, timestr);
 
   if (procname) {
-    _LOG(log, SCOPE_AT_FAULT, "Cmd line: %s\n", procname);
+    _LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", procname);
   }
 }
 
 static void dump_process_footer(log_t* log, pid_t pid) {
-  _LOG(log, SCOPE_AT_FAULT, "\n----- end %d -----\n", pid);
+  _LOG(log, logtype::BACKTRACE, "\n----- end %d -----\n", pid);
 }
 
 static void dump_thread(
@@ -79,10 +81,10 @@
     }
   }
 
-  _LOG(log, SCOPE_AT_FAULT, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid);
+  _LOG(log, logtype::BACKTRACE, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid);
 
   if (!attached && ptrace(PTRACE_ATTACH, tid, 0, 0) < 0) {
-    _LOG(log, SCOPE_AT_FAULT, "Could not attach to thread: %s\n", strerror(errno));
+    _LOG(log, logtype::BACKTRACE, "Could not attach to thread: %s\n", strerror(errno));
     return;
   }
 
@@ -90,11 +92,11 @@
 
   UniquePtr<Backtrace> backtrace(Backtrace::Create(tid, BACKTRACE_CURRENT_THREAD));
   if (backtrace->Unwind(0)) {
-    dump_backtrace_to_log(backtrace.get(), log, SCOPE_AT_FAULT, "  ");
+    dump_backtrace_to_log(backtrace.get(), log, "  ");
   }
 
   if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
-    LOG("ptrace detach from %d failed: %s\n", tid, strerror(errno));
+    _LOG(log, logtype::ERROR, "ptrace detach from %d failed: %s\n", tid, strerror(errno));
     *detach_failed = true;
   }
 }
@@ -104,7 +106,6 @@
   log_t log;
   log.tfd = fd;
   log.amfd = amfd;
-  log.quiet = true;
 
   dump_process_header(&log, pid);
   dump_thread(&log, tid, true, detach_failed, total_sleep_time_usec);
@@ -133,9 +134,8 @@
   dump_process_footer(&log, pid);
 }
 
-void dump_backtrace_to_log(Backtrace* backtrace, log_t* log,
-                           int scope_flags, const char* prefix) {
+void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix) {
   for (size_t i = 0; i < backtrace->NumFrames(); i++) {
-    _LOG(log, scope_flags, "%s%s\n", prefix, backtrace->FormatFrameData(i).c_str());
+    _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, backtrace->FormatFrameData(i).c_str());
   }
 }
diff --git a/debuggerd/backtrace.h b/debuggerd/backtrace.h
index 2ec8afb..da14cd4 100644
--- a/debuggerd/backtrace.h
+++ b/debuggerd/backtrace.h
@@ -29,7 +29,6 @@
                     int* total_sleep_time_usec);
 
 /* Dumps the backtrace in the backtrace data structure to the log. */
-void dump_backtrace_to_log(Backtrace* backtrace, log_t* log,
-                           int scope_flags, const char* prefix);
+void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix);
 
 #endif // _DEBUGGERD_BACKTRACE_H
diff --git a/debuggerd/crasher.c b/debuggerd/crasher.c
index 5ecb1a5..9df3c64 100644
--- a/debuggerd/crasher.c
+++ b/debuggerd/crasher.c
@@ -1,21 +1,24 @@
-
-//#include <cutils/misc.h>
-
-#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sched.h>
-#include <errno.h>
-
-#include <signal.h>
+#include <sys/cdefs.h>
+#include <sys/mman.h>
 #include <sys/ptrace.h>
-#include <sys/wait.h>
 #include <sys/socket.h>
-
-#include <pthread.h>
+#include <sys/wait.h>
+#include <unistd.h>
 
 #include <cutils/sockets.h>
+#include <log/log.h>
+
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
 
 extern const char* __progname;
 
@@ -23,26 +26,13 @@
 void crashnostack(void);
 static int do_action(const char* arg);
 
-static void debuggerd_connect()
-{
-    char tmp[1];
-    int s;
-    sprintf(tmp, "%d", gettid());
-    s = socket_local_client("android:debuggerd",
-            ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
-    if(s >= 0) {
-        read(s, tmp, 1);
-        close(s);
-    }
-}
-
-static void maybeabort() {
-    if(time(0) != 42) {
+static void maybe_abort() {
+    if (time(0) != 42) {
         abort();
     }
 }
 
-static int smash_stack(int i) {
+static int smash_stack(int i __unused) {
     printf("crasher: deliberately corrupting stack...\n");
     // Unless there's a "big enough" buffer on the stack, gcc
     // doesn't bother inserting checks.
@@ -63,20 +53,15 @@
     overflow_stack(&buf);
 }
 
-static void test_call1()
-{
-    *((int*) 32) = 1;
-}
-
 static void *noisy(void *x)
 {
-    char c = (unsigned) x;
+    char c = (uintptr_t) x;
     for(;;) {
         usleep(250*1000);
         write(2, &c, 1);
         if(c == 'C') *((unsigned*) 0) = 42;
     }
-    return 0;
+    return NULL;
 }
 
 static int ctest()
@@ -94,7 +79,7 @@
 
 static void* thread_callback(void* raw_arg)
 {
-    return (void*) do_action((const char*) raw_arg);
+    return (void*) (uintptr_t) do_action((const char*) raw_arg);
 }
 
 static int do_action_on_thread(const char* arg)
@@ -103,7 +88,7 @@
     pthread_create(&t, NULL, thread_callback, (void*) arg);
     void* result = NULL;
     pthread_join(t, &result);
-    return (int) result;
+    return (int) (uintptr_t) result;
 }
 
 __attribute__((noinline)) static int crash3(int a) {
@@ -126,41 +111,77 @@
     free((void*) buf); // GCC is smart enough to warn about this, but we're doing it deliberately.
 }
 
+static void sigsegv_non_null() {
+    int* a = (int *)(&do_action);
+    *a = 42;
+}
+
 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")) {
+    } else if (!strcmp(arg, "SIGSEGV-non-null")) {
+        sigsegv_non_null();
+    } else if (!strcmp(arg, "smash-stack")) {
         return smash_stack(42);
-    } else if (!strcmp(arg,"stack-overflow")) {
+    } else if (!strcmp(arg, "stack-overflow")) {
         overflow_stack(NULL);
-    } else if (!strcmp(arg,"nostack")) {
+    } else if (!strcmp(arg, "nostack")) {
         crashnostack();
-    } else if (!strcmp(arg,"ctest")) {
+    } else if (!strcmp(arg, "ctest")) {
         return ctest();
-    } else if (!strcmp(arg,"exit")) {
+    } else if (!strcmp(arg, "exit")) {
         exit(1);
-    } else if (!strcmp(arg,"crash")) {
+    } else if (!strcmp(arg, "crash") || !strcmp(arg, "SIGSEGV")) {
         return crash(42);
-    } else if (!strcmp(arg,"abort")) {
-        maybeabort();
+    } else if (!strcmp(arg, "abort")) {
+        maybe_abort();
+    } else if (!strcmp(arg, "assert")) {
+        __assert("some_file.c", 123, "false");
+    } else if (!strcmp(arg, "assert2")) {
+      __assert2("some_file.c", 123, "some_function", "false");
+    } else if (!strcmp(arg, "LOG_ALWAYS_FATAL")) {
+        LOG_ALWAYS_FATAL("hello %s", "world");
+    } else if (!strcmp(arg, "LOG_ALWAYS_FATAL_IF")) {
+        LOG_ALWAYS_FATAL_IF(true, "hello %s", "world");
+    } else if (!strcmp(arg, "SIGPIPE")) {
+        int pipe_fds[2];
+        pipe(pipe_fds);
+        close(pipe_fds[0]);
+        write(pipe_fds[1], "oops", 4);
+        return EXIT_SUCCESS;
+    } else if (!strcmp(arg, "SIGTRAP")) {
+        raise(SIGTRAP);
+        return EXIT_SUCCESS;
     } else if (!strcmp(arg, "heap-usage")) {
         abuse_heap();
+    } else if (!strcmp(arg, "SIGSEGV-unmapped")) {
+        char* map = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+        munmap(map, sizeof(int));
+        map[0] = '8';
     }
 
     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, "  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, "  abort                 call abort()\n");
+    fprintf(stderr, "  assert                call assert() without a function\n");
+    fprintf(stderr, "  assert2               call assert() with a function\n");
+    fprintf(stderr, "  LOG_ALWAYS_FATAL      call LOG_ALWAYS_FATAL\n");
+    fprintf(stderr, "  LOG_ALWAYS_FATAL_IF   call LOG_ALWAYS_FATAL\n");
+    fprintf(stderr, "  SIGPIPE               cause a SIGPIPE\n");
+    fprintf(stderr, "  SIGSEGV               cause a SIGSEGV at address 0x0 (synonym: crash)\n");
+    fprintf(stderr, "  SIGSEGV-non-null      cause a SIGSEGV at a non-zero address\n");
+    fprintf(stderr, "  SIGSEGV-unmapped      mmap/munmap a region of memory and then attempt to access it\n");
+    fprintf(stderr, "  SIGTRAP               cause a SIGTRAP\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;
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index de8ba9d..61805c9 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -30,7 +30,6 @@
 #include <sys/stat.h>
 #include <sys/poll.h>
 
-#include <log/logd.h>
 #include <log/logger.h>
 
 #include <cutils/sockets.h>
@@ -46,105 +45,55 @@
 #include "tombstone.h"
 #include "utility.h"
 
-typedef struct {
+struct debugger_request_t {
   debugger_action_t action;
   pid_t pid, tid;
   uid_t uid, gid;
   uintptr_t abort_msg_address;
-} debugger_request_t;
+  int32_t original_si_code;
+};
 
-static int write_string(const char* file, const char* string) {
-  int len;
-  int fd;
-  ssize_t amt;
-  fd = open(file, O_RDWR);
-  len = strlen(string);
-  if (fd < 0)
-    return -errno;
-  amt = write(fd, string, len);
-  close(fd);
-  return amt >= 0 ? 0 : -errno;
-}
+static void wait_for_user_action(const debugger_request_t &request) {
+  // Find out the name of the process that crashed.
+  char path[64];
+  snprintf(path, sizeof(path), "/proc/%d/exe", request.pid);
 
-static void init_debug_led() {
-  // trout leds
-  write_string("/sys/class/leds/red/brightness", "0");
-  write_string("/sys/class/leds/green/brightness", "0");
-  write_string("/sys/class/leds/blue/brightness", "0");
-  write_string("/sys/class/leds/red/device/blink", "0");
-  // sardine leds
-  write_string("/sys/class/leds/left/cadence", "0,0");
-}
+  char exe[PATH_MAX];
+  int count;
+  if ((count = readlink(path, exe, sizeof(exe) - 1)) == -1) {
+    ALOGE("readlink('%s') failed: %s", path, strerror(errno));
+    strlcpy(exe, "unknown", sizeof(exe));
+  } else {
+    exe[count] = '\0';
+  }
 
-static void enable_debug_led() {
-  // trout leds
-  write_string("/sys/class/leds/red/brightness", "255");
-  // sardine leds
-  write_string("/sys/class/leds/left/cadence", "1,0");
-}
+  // Explain how to attach the debugger.
+  ALOGI("********************************************************\n"
+        "* Process %d has been suspended while crashing.\n"
+        "* To attach gdbserver for a gdb connection on port 5039\n"
+        "* and start gdbclient:\n"
+        "*\n"
+        "*     gdbclient %s :5039 %d\n"
+        "*\n"
+        "* Wait for gdb to start, then press the VOLUME DOWN key\n"
+        "* to let the process continue crashing.\n"
+        "********************************************************\n",
+        request.pid, exe, request.tid);
 
-static void disable_debug_led() {
-  // trout leds
-  write_string("/sys/class/leds/red/brightness", "0");
-  // sardine leds
-  write_string("/sys/class/leds/left/cadence", "0,0");
-}
-
-static void wait_for_user_action(pid_t pid) {
-  // First log a helpful message
-  LOG(    "********************************************************\n"
-          "* Process %d has been suspended while crashing.  To\n"
-          "* attach gdbserver for a gdb connection on port 5039\n"
-          "* and start gdbclient:\n"
-          "*\n"
-          "*     gdbclient app_process :5039 %d\n"
-          "*\n"
-          "* Wait for gdb to start, then press HOME or VOLUME DOWN key\n"
-          "* to let the process continue crashing.\n"
-          "********************************************************\n",
-          pid, pid);
-
-  // wait for HOME or VOLUME DOWN key
+  // Wait for VOLUME DOWN.
   if (init_getevent() == 0) {
-    int ms = 1200 / 10;
-    int dit = 1;
-    int dah = 3*dit;
-    int _       = -dit;
-    int ___     = 3*_;
-    int _______ = 7*_;
-    const int codes[] = {
-      dit,_,dit,_,dit,___,dah,_,dah,_,dah,___,dit,_,dit,_,dit,_______
-    };
-    size_t s = 0;
-    struct input_event e;
-    bool done = false;
-    init_debug_led();
-    enable_debug_led();
-    do {
-      int timeout = abs(codes[s]) * ms;
-      int res = get_event(&e, timeout);
-      if (res == 0) {
-        if (e.type == EV_KEY
-            && (e.code == KEY_HOME || e.code == KEY_VOLUMEDOWN)
-            && e.value == 0) {
-          done = true;
-        }
-      } else if (res == 1) {
-        if (++s >= sizeof(codes)/sizeof(*codes))
-          s = 0;
-        if (codes[s] > 0) {
-          enable_debug_led();
-        } else {
-          disable_debug_led();
+    while (true) {
+      input_event e;
+      if (get_event(&e, -1) == 0) {
+        if (e.type == EV_KEY && e.code == KEY_VOLUMEDOWN && e.value == 0) {
+          break;
         }
       }
-    } while (!done);
+    }
     uninit_getevent();
   }
 
-  // don't forget to turn debug led off
-  disable_debug_led();
-  LOG("debuggerd resuming process %d", pid);
+  ALOGI("debuggerd resuming process %d", request.pid);
 }
 
 static int get_process_info(pid_t tid, pid_t* out_pid, uid_t* out_uid, uid_t* out_gid) {
@@ -176,24 +125,24 @@
 }
 
 static int read_request(int fd, debugger_request_t* out_request) {
-  struct ucred cr;
-  int len = sizeof(cr);
+  ucred cr;
+  socklen_t len = sizeof(cr);
   int status = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
   if (status != 0) {
-    LOG("cannot get credentials\n");
+    ALOGE("cannot get credentials\n");
     return -1;
   }
 
-  XLOG("reading tid\n");
+  ALOGV("reading tid\n");
   fcntl(fd, F_SETFL, O_NONBLOCK);
 
-  struct pollfd pollfds[1];
+  pollfd pollfds[1];
   pollfds[0].fd = fd;
   pollfds[0].events = POLLIN;
   pollfds[0].revents = 0;
   status = TEMP_FAILURE_RETRY(poll(pollfds, 1, 3000));
   if (status != 1) {
-    LOG("timed out reading tid (from pid=%d uid=%d)\n", cr.pid, cr.uid);
+    ALOGE("timed out reading tid (from pid=%d uid=%d)\n", cr.pid, cr.uid);
     return -1;
   }
 
@@ -201,13 +150,11 @@
   memset(&msg, 0, sizeof(msg));
   status = TEMP_FAILURE_RETRY(read(fd, &msg, sizeof(msg)));
   if (status < 0) {
-    LOG("read failure? %s (pid=%d uid=%d)\n", strerror(errno), cr.pid, cr.uid);
+    ALOGE("read failure? %s (pid=%d uid=%d)\n", strerror(errno), cr.pid, cr.uid);
     return -1;
   }
-  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);
+  if (status != sizeof(debugger_msg_t)) {
+    ALOGE("invalid crash request of size %d (from pid=%d uid=%d)\n", status, cr.pid, cr.uid);
     return -1;
   }
 
@@ -217,6 +164,7 @@
   out_request->uid = cr.uid;
   out_request->gid = cr.gid;
   out_request->abort_msg_address = msg.abort_msg_address;
+  out_request->original_si_code = msg.original_si_code;
 
   if (msg.action == DEBUGGER_ACTION_CRASH) {
     // Ensure that the tid reported by the crashing process is valid.
@@ -224,7 +172,7 @@
     struct stat s;
     snprintf(buf, sizeof buf, "/proc/%d/task/%d", out_request->pid, out_request->tid);
     if (stat(buf, &s)) {
-      LOG("tid %d does not exist in pid %d. ignoring debug request\n",
+      ALOGE("tid %d does not exist in pid %d. ignoring debug request\n",
           out_request->tid, out_request->pid);
       return -1;
     }
@@ -235,7 +183,7 @@
     status = get_process_info(out_request->tid, &out_request->pid,
                               &out_request->uid, &out_request->gid);
     if (status < 0) {
-      LOG("tid %d does not exist. ignoring explicit dump request\n", out_request->tid);
+      ALOGE("tid %d does not exist. ignoring explicit dump request\n", out_request->tid);
       return -1;
     }
   } else {
@@ -256,13 +204,13 @@
 }
 
 static void handle_request(int fd) {
-  XLOG("handle_request(%d)\n", fd);
+  ALOGV("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",
+    ALOGV("BOOM: pid=%d uid=%d gid=%d tid=%d\n",
          request.pid, request.uid, request.gid, request.tid);
 
     // At this point, the thread that made the request is blocked in
@@ -276,12 +224,12 @@
     // See details in bionic/libc/linker/debugger.c, in function
     // debugger_signal_handler().
     if (ptrace(PTRACE_ATTACH, request.tid, 0, 0)) {
-      LOG("ptrace attach failed: %s\n", strerror(errno));
+      ALOGE("ptrace attach failed: %s\n", strerror(errno));
     } else {
       bool detach_failed = false;
       bool attach_gdb = should_attach_gdb(&request);
       if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
-        LOG("failed responding to client: %s\n", strerror(errno));
+        ALOGE("failed responding to client: %s\n", strerror(errno));
       } else {
         char* tombstone_path = NULL;
 
@@ -300,34 +248,36 @@
           switch (signal) {
             case SIGSTOP:
               if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
-                XLOG("stopped -- dumping to tombstone\n");
-                tombstone_path = engrave_tombstone(
-                    request.pid, request.tid, signal, request.abort_msg_address, true, true,
-                    &detach_failed, &total_sleep_time_usec);
+                ALOGV("stopped -- dumping to tombstone\n");
+                tombstone_path = engrave_tombstone(request.pid, request.tid,
+                                                   signal, request.original_si_code,
+                                                   request.abort_msg_address, true,
+                                                   &detach_failed, &total_sleep_time_usec);
               } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
-                XLOG("stopped -- dumping to fd\n");
+                ALOGV("stopped -- dumping to fd\n");
                 dump_backtrace(fd, -1, request.pid, request.tid, &detach_failed,
                                &total_sleep_time_usec);
               } else {
-                XLOG("stopped -- continuing\n");
+                ALOGV("stopped -- continuing\n");
                 status = ptrace(PTRACE_CONT, request.tid, 0, 0);
                 if (status) {
-                  LOG("ptrace continue failed: %s\n", strerror(errno));
+                  ALOGE("ptrace continue failed: %s\n", strerror(errno));
                 }
                 continue; // loop again
               }
               break;
 
-            case SIGILL:
             case SIGABRT:
             case SIGBUS:
             case SIGFPE:
-            case SIGSEGV:
+            case SIGILL:
             case SIGPIPE:
+            case SIGSEGV:
 #ifdef SIGSTKFLT
             case SIGSTKFLT:
 #endif
-              XLOG("stopped -- fatal signal\n");
+            case SIGTRAP:
+              ALOGV("stopped -- fatal signal\n");
               // Send a SIGSTOP to the process to make all of
               // the non-signaled threads stop moving.  Without
               // this we get a lot of "ptrace detach failed:
@@ -335,14 +285,14 @@
               kill(request.pid, SIGSTOP);
               // 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, request.abort_msg_address, !attach_gdb,
-                  false, &detach_failed, &total_sleep_time_usec);
+              tombstone_path = engrave_tombstone(request.pid, request.tid,
+                                                 signal, request.original_si_code,
+                                                 request.abort_msg_address, !attach_gdb,
+                                                 &detach_failed, &total_sleep_time_usec);
               break;
 
             default:
-              XLOG("stopped -- unexpected signal\n");
-              LOG("process stopped due to unexpected signal %d\n", signal);
+              ALOGE("process stopped due to unexpected signal %d\n", signal);
               break;
           }
           break;
@@ -358,14 +308,14 @@
         free(tombstone_path);
       }
 
-      XLOG("detaching\n");
+      ALOGV("detaching\n");
       if (attach_gdb) {
         // stop the process so we can debug
         kill(request.pid, SIGSTOP);
 
         // detach so we can attach gdbserver
         if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
-          LOG("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
+          ALOGE("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
           detach_failed = true;
         }
 
@@ -373,11 +323,11 @@
         // for user action for the crashing process.
         // in this case, we log a message and turn the debug LED on
         // waiting for a gdb connection (for instance)
-        wait_for_user_action(request.pid);
+        wait_for_user_action(request);
       } else {
         // just detach
         if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
-          LOG("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
+          ALOGE("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
           detach_failed = true;
         }
       }
@@ -389,7 +339,7 @@
       // actual parent won't receive a death notification via wait(2).  At this point
       // there's not much we can do about that.
       if (detach_failed) {
-        LOG("debuggerd committing suicide to free the zombie!\n");
+        ALOGE("debuggerd committing suicide to free the zombie!\n");
         kill(getpid(), SIGKILL);
       }
     }
@@ -401,54 +351,50 @@
 }
 
 static int do_server() {
-  int s;
-  struct sigaction act;
-  int logsocket = -1;
-
-  // debuggerd crashes can't be reported to debuggerd.  Reset all of the
-  // crash handlers.
-  signal(SIGILL, SIG_DFL);
+  // debuggerd crashes can't be reported to debuggerd.
+  // Reset all of the crash handlers.
   signal(SIGABRT, SIG_DFL);
   signal(SIGBUS, SIG_DFL);
   signal(SIGFPE, SIG_DFL);
+  signal(SIGILL, SIG_DFL);
   signal(SIGSEGV, SIG_DFL);
 #ifdef SIGSTKFLT
   signal(SIGSTKFLT, SIG_DFL);
 #endif
+  signal(SIGTRAP, SIG_DFL);
 
   // Ignore failed writes to closed sockets
   signal(SIGPIPE, SIG_IGN);
 
-  logsocket = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM);
+  int logsocket = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM);
   if (logsocket < 0) {
     logsocket = -1;
   } else {
     fcntl(logsocket, F_SETFD, FD_CLOEXEC);
   }
 
+  struct sigaction act;
   act.sa_handler = SIG_DFL;
   sigemptyset(&act.sa_mask);
   sigaddset(&act.sa_mask,SIGCHLD);
   act.sa_flags = SA_NOCLDWAIT;
   sigaction(SIGCHLD, &act, 0);
 
-  s = socket_local_server(DEBUGGER_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+  int s = socket_local_server(DEBUGGER_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
   if (s < 0)
     return 1;
   fcntl(s, F_SETFD, FD_CLOEXEC);
 
-  LOG("debuggerd: " __DATE__ " " __TIME__ "\n");
+  ALOGI("debuggerd: " __DATE__ " " __TIME__ "\n");
 
   for (;;) {
-    struct sockaddr addr;
-    socklen_t alen;
-    int fd;
+    sockaddr addr;
+    socklen_t alen = sizeof(addr);
 
-    alen = sizeof(addr);
-    XLOG("waiting for connection\n");
-    fd = accept(s, &addr, &alen);
+    ALOGV("waiting for connection\n");
+    int fd = accept(s, &addr, &alen);
     if (fd < 0) {
-      XLOG("accept failed: %s\n", strerror(errno));
+      ALOGV("accept failed: %s\n", strerror(errno));
       continue;
     }
 
diff --git a/debuggerd/machine.h b/debuggerd/machine.h
index 2f1e201..fca9fbe 100644
--- a/debuggerd/machine.h
+++ b/debuggerd/machine.h
@@ -21,7 +21,7 @@
 
 #include "utility.h"
 
-void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags);
-void dump_registers(log_t* log, pid_t tid, int scope_flags);
+void dump_memory_and_code(log_t* log, pid_t tid);
+void dump_registers(log_t* log, pid_t tid);
 
 #endif // _DEBUGGERD_MACHINE_H
diff --git a/debuggerd/mips/machine.cpp b/debuggerd/mips/machine.cpp
index d1a7f2d..97834c7 100644
--- a/debuggerd/mips/machine.cpp
+++ b/debuggerd/mips/machine.cpp
@@ -22,141 +22,91 @@
 #include <sys/types.h>
 #include <sys/ptrace.h>
 
-#include <corkscrew/ptrace.h>
-
 #include <sys/user.h>
 
 #include "../utility.h"
 #include "../machine.h"
 
-// enable to dump memory pointed to by every register
-#define DUMP_MEMORY_FOR_ALL_REGISTERS 1
-
 #define R(x) (static_cast<unsigned int>(x))
 
-static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) {
-  char code_buffer[64];       // actual 8+1+((8+1)*4) + 1 == 45
-  char ascii_buffer[32];      // actual 16 + 1 == 17
-  uintptr_t p, end;
-
-  p = addr & ~3;
-  p -= 32;
-  if (p > addr) {
-    // catch underflow
-    p = 0;
-  }
-  end = p + 80;
-  // catch overflow; 'end - p' has to be multiples of 16
-  while (end < p)
-    end -= 16;
-
-  // Dump the code around PC as:
-  //  addr     contents                             ascii
-  //  00008d34 ef000000 e8bd0090 e1b00000 512fff1e  ............../Q
-  //  00008d44 ea00b1f9 e92d0090 e3a070fc ef000000  ......-..p......
-  while (p < end) {
-    char* asc_out = ascii_buffer;
-
-    sprintf(code_buffer, "%08x ", p);
-
-    int i;
-    for (i = 0; i < 4; i++) {
-      // If we see (data == -1 && errno != 0), we know that the ptrace
-      // call failed, probably because we're dumping memory in an
-      // unmapped or inaccessible page.  I don't know if there's
-      // value in making that explicit in the output -- it likely
-      // just complicates parsing and clarifies nothing for the
-      // enlightened reader.
-      long data = ptrace(PTRACE_PEEKTEXT, tid, (void*)p, NULL);
-      sprintf(code_buffer + strlen(code_buffer), "%08lx ", data);
-
-      int j;
-      for (j = 0; j < 4; j++) {
-        // Our isprint() allows high-ASCII characters that display
-        // differently (often badly) in different viewers, so we
-        // just use a simpler test.
-        char val = (data >> (j*8)) & 0xff;
-        if (val >= 0x20 && val < 0x7f) {
-          *asc_out++ = val;
-        } else {
-          *asc_out++ = '.';
-        }
-      }
-      p += 4;
-    }
-    *asc_out = '\0';
-    _LOG(log, scope_flags, "    %s %s\n", code_buffer, ascii_buffer);
-  }
-}
+// The MIPS uapi ptrace.h has the wrong definition for pt_regs. PTRACE_GETREGS
+// writes 64-bit quantities even though the public struct uses 32-bit ones.
+struct pt_regs_mips_t {
+  uint64_t regs[32];
+  uint64_t lo;
+  uint64_t hi;
+  uint64_t cp0_epc;
+  uint64_t cp0_badvaddr;
+  uint64_t cp0_status;
+  uint64_t cp0_cause;
+};
 
 // If configured to do so, dump memory around *all* registers
 // for the crashing thread.
-void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
+void dump_memory_and_code(log_t* log, pid_t tid) {
   pt_regs_mips_t r;
   if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
     return;
   }
 
-  if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) {
-    static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
+  static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
 
-    for (int reg = 0; reg < 32; reg++) {
-      // skip uninteresting registers
-      if (reg == 0 // $0
-          || reg == 26 // $k0
-          || reg == 27 // $k1
-          || reg == 31 // $ra (done below)
-         )
-        continue;
+  for (int reg = 0; reg < 32; reg++) {
+    // skip uninteresting registers
+    if (reg == 0 // $0
+        || reg == 26 // $k0
+        || reg == 27 // $k1
+        || reg == 31 // $ra (done below)
+       )
+      continue;
 
-      uintptr_t addr = R(r.regs[reg]);
+    uintptr_t addr = R(r.regs[reg]);
 
-      // Don't bother if it looks like a small int or ~= null, or if
-      // it's in the kernel area.
-      if (addr < 4096 || addr >= 0x80000000) {
-        continue;
-      }
-
-      _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
-      dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE);
+    // Don't bother if it looks like a small int or ~= null, or if
+    // it's in the kernel area.
+    if (addr < 4096 || addr >= 0x80000000) {
+      continue;
     }
+
+    _LOG(log, logtype::MEMORY, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
+    dump_memory(log, tid, addr);
   }
 
   unsigned int pc = R(r.cp0_epc);
   unsigned int ra = R(r.regs[31]);
 
-  _LOG(log, scope_flags, "\ncode around pc:\n");
-  dump_memory(log, tid, (uintptr_t)pc, scope_flags);
+  _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
+  dump_memory(log, tid, (uintptr_t)pc);
 
   if (pc != ra) {
-    _LOG(log, scope_flags, "\ncode around ra:\n");
-    dump_memory(log, tid, (uintptr_t)ra, scope_flags);
+    _LOG(log, logtype::MEMORY, "\ncode around ra:\n");
+    dump_memory(log, tid, (uintptr_t)ra);
   }
 }
 
-void dump_registers(log_t* log, pid_t tid, int scope_flags) {
+void dump_registers(log_t* log, pid_t tid) {
   pt_regs_mips_t r;
   if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
-    _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
     return;
   }
 
-  _LOG(log, scope_flags, " zr %08x  at %08x  v0 %08x  v1 %08x\n",
+  _LOG(log, logtype::REGISTERS, " 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, scope_flags, " a0 %08x  a1 %08x  a2 %08x  a3 %08x\n",
+  _LOG(log, logtype::REGISTERS, " 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, scope_flags, " t0 %08x  t1 %08x  t2 %08x  t3 %08x\n",
+  _LOG(log, logtype::REGISTERS, " 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, scope_flags, " t4 %08x  t5 %08x  t6 %08x  t7 %08x\n",
+  _LOG(log, logtype::REGISTERS, " 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, scope_flags, " s0 %08x  s1 %08x  s2 %08x  s3 %08x\n",
+  _LOG(log, logtype::REGISTERS, " 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, scope_flags, " s4 %08x  s5 %08x  s6 %08x  s7 %08x\n",
+  _LOG(log, logtype::REGISTERS, " 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, scope_flags, " t8 %08x  t9 %08x  k0 %08x  k1 %08x\n",
+  _LOG(log, logtype::REGISTERS, " 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, scope_flags, " gp %08x  sp %08x  s8 %08x  ra %08x\n",
+  _LOG(log, logtype::REGISTERS, " 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, scope_flags, " hi %08x  lo %08x bva %08x epc %08x\n",
+  _LOG(log, logtype::REGISTERS, " 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.cpp b/debuggerd/tombstone.cpp
old mode 100644
new mode 100755
index c9a2376..f41166b
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -14,31 +14,33 @@
  * limitations under the License.
  */
 
-#include <stddef.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <string.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <errno.h>
+#define LOG_TAG "DEBUG"
+
 #include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <time.h>
 #include <sys/ptrace.h>
+#include <sys/socket.h>
 #include <sys/stat.h>
-#include <inttypes.h>
+#include <sys/un.h>
 
 #include <private/android_filesystem_config.h>
 
+#include <cutils/properties.h>
 #include <log/log.h>
 #include <log/logger.h>
-#include <cutils/properties.h>
+#include <log/logprint.h>
 
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 
-#include <sys/socket.h>
-#include <linux/un.h>
-
 #include <selinux/android.h>
 
 #include <UniquePtr.h>
@@ -51,22 +53,17 @@
 
 #define MAX_TOMBSTONES  10
 #define TOMBSTONE_DIR   "/data/tombstones"
+#define TOMBSTONE_TEMPLATE (TOMBSTONE_DIR"/tombstone_%02d")
 
 // 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;     \
-  (void)(&__dummy1 == &__dummy2); }
-
-
-static bool signal_has_address(int sig) {
+static bool signal_has_si_addr(int sig) {
   switch (sig) {
-    case SIGILL:
-    case SIGFPE:
-    case SIGSEGV:
     case SIGBUS:
+    case SIGFPE:
+    case SIGILL:
+    case SIGSEGV:
       return true;
     default:
       return false;
@@ -75,16 +72,17 @@
 
 static const char* get_signame(int sig) {
   switch(sig) {
-    case SIGILL: return "SIGILL";
     case SIGABRT: return "SIGABRT";
     case SIGBUS: return "SIGBUS";
     case SIGFPE: return "SIGFPE";
-    case SIGSEGV: return "SIGSEGV";
+    case SIGILL: return "SIGILL";
     case SIGPIPE: return "SIGPIPE";
-#ifdef SIGSTKFLT
+    case SIGSEGV: return "SIGSEGV";
+#if defined(SIGSTKFLT)
     case SIGSTKFLT: return "SIGSTKFLT";
 #endif
     case SIGSTOP: return "SIGSTOP";
+    case SIGTRAP: return "SIGTRAP";
     default: return "?";
   }
 }
@@ -103,13 +101,17 @@
         case ILL_COPROC: return "ILL_COPROC";
         case ILL_BADSTK: return "ILL_BADSTK";
       }
+      static_assert(NSIGILL == ILL_BADSTK, "missing ILL_* si_code");
       break;
     case SIGBUS:
       switch (code) {
         case BUS_ADRALN: return "BUS_ADRALN";
         case BUS_ADRERR: return "BUS_ADRERR";
         case BUS_OBJERR: return "BUS_OBJERR";
+        case BUS_MCEERR_AR: return "BUS_MCEERR_AR";
+        case BUS_MCEERR_AO: return "BUS_MCEERR_AO";
       }
+      static_assert(NSIGBUS == BUS_MCEERR_AO, "missing BUS_* si_code");
       break;
     case SIGFPE:
       switch (code) {
@@ -122,74 +124,76 @@
         case FPE_FLTINV: return "FPE_FLTINV";
         case FPE_FLTSUB: return "FPE_FLTSUB";
       }
+      static_assert(NSIGFPE == FPE_FLTSUB, "missing FPE_* si_code");
       break;
     case SIGSEGV:
       switch (code) {
         case SEGV_MAPERR: return "SEGV_MAPERR";
         case SEGV_ACCERR: return "SEGV_ACCERR";
       }
+      static_assert(NSIGSEGV == SEGV_ACCERR, "missing SEGV_* si_code");
       break;
     case SIGTRAP:
       switch (code) {
         case TRAP_BRKPT: return "TRAP_BRKPT";
         case TRAP_TRACE: return "TRAP_TRACE";
+        case TRAP_BRANCH: return "TRAP_BRANCH";
+        case TRAP_HWBKPT: return "TRAP_HWBKPT";
       }
+      static_assert(NSIGTRAP == TRAP_HWBKPT, "missing TRAP_* si_code");
       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
+    case SI_DETHREAD: return "SI_DETHREAD";
   }
   // Then give up...
   return "?";
 }
 
-static void dump_revision_info(log_t* log) {
+static void dump_header_info(log_t* log) {
+  char fingerprint[PROPERTY_VALUE_MAX];
   char revision[PROPERTY_VALUE_MAX];
 
+  property_get("ro.build.fingerprint", fingerprint, "unknown");
   property_get("ro.revision", revision, "unknown");
 
-  _LOG(log, SCOPE_AT_FAULT, "Revision: '%s'\n", revision);
+  _LOG(log, logtype::HEADER, "Build fingerprint: '%s'\n", fingerprint);
+  _LOG(log, logtype::HEADER, "Revision: '%s'\n", revision);
+  _LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING);
 }
 
-static void dump_build_info(log_t* log) {
-  char fingerprint[PROPERTY_VALUE_MAX];
-
-  property_get("ro.build.fingerprint", fingerprint, "unknown");
-
-  _LOG(log, SCOPE_AT_FAULT, "Build fingerprint: '%s'\n", fingerprint);
-}
-
-static void dump_fault_addr(log_t* log, pid_t tid, int sig) {
+static void dump_signal_info(log_t* log, pid_t tid, int signal, int si_code) {
   siginfo_t si;
-
   memset(&si, 0, sizeof(si));
-  if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)){
-    _LOG(log, SCOPE_AT_FAULT, "cannot get siginfo: %s\n", strerror(errno));
-  } else if (signal_has_address(sig)) {
-    _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr %0*" PRIxPTR "\n",
-         sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code),
-         sizeof(uintptr_t)*2, reinterpret_cast<uintptr_t>(si.si_addr));
-  } else {
-    _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));
+  if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si) == -1) {
+    _LOG(log, logtype::HEADER, "cannot get siginfo: %s\n", strerror(errno));
+    return;
   }
+
+  // bionic has to re-raise some signals, which overwrites the si_code with SI_TKILL.
+  si.si_code = si_code;
+
+  char addr_desc[32]; // ", fault addr 0x1234"
+  if (signal_has_si_addr(signal)) {
+    snprintf(addr_desc, sizeof(addr_desc), "%p", si.si_addr);
+  } else {
+    snprintf(addr_desc, sizeof(addr_desc), "--------");
+  }
+
+  _LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s), fault addr %s\n",
+       signal, get_signame(signal), si.si_code, get_sigcode(signal, si.si_code), addr_desc);
 }
 
-static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, int scope_flags) {
+static void dump_thread_info(log_t* log, pid_t pid, pid_t tid) {
   char path[64];
   char threadnamebuf[1024];
   char* threadname = NULL;
@@ -207,27 +211,23 @@
     }
   }
 
-  if (IS_AT_FAULT(scope_flags)) {
-    char procnamebuf[1024];
-    char* procname = NULL;
+  char procnamebuf[1024];
+  char* procname = NULL;
 
-    snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
-    if ((fp = fopen(path, "r"))) {
-      procname = fgets(procnamebuf, sizeof(procnamebuf), fp);
-      fclose(fp);
-    }
-
-    _LOG(log, SCOPE_AT_FAULT, "pid: %d, tid: %d, name: %s  >>> %s <<<\n", pid, tid,
-         threadname ? threadname : "UNKNOWN", procname ? procname : "UNKNOWN");
-  } else {
-    _LOG(log, 0, "pid: %d, tid: %d, name: %s\n", pid, tid, threadname ? threadname : "UNKNOWN");
+  snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
+  if ((fp = fopen(path, "r"))) {
+    procname = fgets(procnamebuf, sizeof(procnamebuf), fp);
+    fclose(fp);
   }
+
+  _LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s  >>> %s <<<\n", pid, tid,
+       threadname ? threadname : "UNKNOWN", procname ? procname : "UNKNOWN");
 }
 
 static void dump_stack_segment(
-    Backtrace* backtrace, log_t* log, int scope_flags, uintptr_t* sp, size_t words, int label) {
+    Backtrace* backtrace, log_t* log, uintptr_t* sp, size_t words, int label) {
   for (size_t i = 0; i < words; i++) {
-    uint32_t stack_content;
+    word_t stack_content;
     if (!backtrace->ReadWord(*sp, &stack_content)) {
       break;
     }
@@ -244,36 +244,36 @@
     if (!func_name.empty()) {
       if (!i && label >= 0) {
         if (offset) {
-          _LOG(log, scope_flags, "    #%02d  %08x  %08x  %s (%s+%u)\n",
+          _LOG(log, logtype::STACK, "    #%02d  %" PRIPTR "  %" PRIPTR "  %s (%s+%" PRIuPTR ")\n",
                label, *sp, stack_content, map_name, func_name.c_str(), offset);
         } else {
-          _LOG(log, scope_flags, "    #%02d  %08x  %08x  %s (%s)\n",
+          _LOG(log, logtype::STACK, "    #%02d  %" PRIPTR "  %" PRIPTR "  %s (%s)\n",
                label, *sp, stack_content, map_name, func_name.c_str());
         }
       } else {
         if (offset) {
-          _LOG(log, scope_flags, "         %08x  %08x  %s (%s+%u)\n",
+          _LOG(log, logtype::STACK, "         %" PRIPTR "  %" PRIPTR "  %s (%s+%" PRIuPTR ")\n",
                *sp, stack_content, map_name, func_name.c_str(), offset);
         } else {
-          _LOG(log, scope_flags, "         %08x  %08x  %s (%s)\n",
+          _LOG(log, logtype::STACK, "         %" PRIPTR "  %" PRIPTR "  %s (%s)\n",
                *sp, stack_content, map_name, func_name.c_str());
         }
       }
     } else {
       if (!i && label >= 0) {
-        _LOG(log, scope_flags, "    #%02d  %08x  %08x  %s\n",
+        _LOG(log, logtype::STACK, "    #%02d  %" PRIPTR "  %" PRIPTR "  %s\n",
              label, *sp, stack_content, map_name);
       } else {
-        _LOG(log, scope_flags, "         %08x  %08x  %s\n",
+        _LOG(log, logtype::STACK, "         %" PRIPTR "  %" PRIPTR "  %s\n",
              *sp, stack_content, map_name);
       }
     }
 
-    *sp += sizeof(uint32_t);
+    *sp += sizeof(word_t);
   }
 }
 
-static void dump_stack(Backtrace* backtrace, log_t* log, int scope_flags) {
+static void dump_stack(Backtrace* backtrace, log_t* log) {
   size_t first = 0, last;
   for (size_t i = 0; i < backtrace->NumFrames(); i++) {
     const backtrace_frame_data_t* frame = backtrace->GetFrame(i);
@@ -289,127 +289,111 @@
   }
   first--;
 
-  scope_flags |= SCOPE_SENSITIVE;
-
   // Dump a few words before the first frame.
-  uintptr_t sp = backtrace->GetFrame(first)->sp - STACK_WORDS * sizeof(uint32_t);
-  dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, -1);
+  word_t sp = backtrace->GetFrame(first)->sp - STACK_WORDS * sizeof(word_t);
+  dump_stack_segment(backtrace, log, &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_data_t* frame = backtrace->GetFrame(i);
     if (sp != frame->sp) {
-      _LOG(log, scope_flags, "         ........  ........\n");
+      _LOG(log, logtype::STACK, "         ........  ........\n");
       sp = frame->sp;
     }
-    if (i - first == 3) {
-      scope_flags &= (~SCOPE_AT_FAULT);
-    }
     if (i == last) {
-      dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, i);
+      dump_stack_segment(backtrace, log, &sp, STACK_WORDS, i);
       if (sp < frame->sp + frame->stack_size) {
-        _LOG(log, scope_flags, "         ........  ........\n");
+        _LOG(log, logtype::STACK, "         ........  ........\n");
       }
     } else {
-      size_t words = frame->stack_size / sizeof(uint32_t);
+      size_t words = frame->stack_size / sizeof(word_t);
       if (words == 0) {
         words = 1;
       } else if (words > STACK_WORDS) {
         words = STACK_WORDS;
       }
-      dump_stack_segment(backtrace, log, scope_flags, &sp, words, i);
+      dump_stack_segment(backtrace, log, &sp, words, i);
     }
   }
 }
 
-static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log, int scope_flags) {
+static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log) {
   if (backtrace->NumFrames()) {
-    _LOG(log, scope_flags, "\nbacktrace:\n");
-    dump_backtrace_to_log(backtrace, log, scope_flags, "    ");
+    _LOG(log, logtype::BACKTRACE, "\nbacktrace:\n");
+    dump_backtrace_to_log(backtrace, log, "    ");
 
-    _LOG(log, scope_flags, "\nstack:\n");
-    dump_stack(backtrace, log, scope_flags);
+    _LOG(log, logtype::STACK, "\nstack:\n");
+    dump_stack(backtrace, log);
   }
 }
 
-static void dump_map(log_t* log, const backtrace_map_t* map, const char* what, int scope_flags) {
-  if (map != NULL) {
-    _LOG(log, scope_flags, "    %08x-%08x %c%c%c %s\n", map->start, map->end,
+static void dump_map(log_t* log, const backtrace_map_t* map, bool fault_addr) {
+  _LOG(log, logtype::MAPS, "%s%" PRIPTR "-%" PRIPTR " %c%c%c  %7" PRIdPTR "  %s\n",
+         (fault_addr? "--->" : "    "), map->start, map->end - 1,
          (map->flags & PROT_READ) ? 'r' : '-', (map->flags & PROT_WRITE) ? 'w' : '-',
-         (map->flags & PROT_EXEC) ? 'x' : '-', map->name.c_str());
-  } else {
-    _LOG(log, scope_flags, "    (no %s)\n", what);
-  }
+         (map->flags & PROT_EXEC) ? 'x' : '-',
+         (map->end - map->start), map->name.c_str());
 }
 
-static void dump_nearby_maps(BacktraceMap* map, log_t* log, pid_t tid, int scope_flags) {
-  scope_flags |= SCOPE_SENSITIVE;
+static void dump_nearby_maps(BacktraceMap* map, log_t* log, pid_t tid) {
   siginfo_t si;
   memset(&si, 0, sizeof(si));
   if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) {
-    _LOG(log, scope_flags, "cannot get siginfo for %d: %s\n", tid, strerror(errno));
-    return;
-  }
-  if (!signal_has_address(si.si_signo)) {
+    _LOG(log, logtype::MAPS, "cannot get siginfo for %d: %s\n", tid, strerror(errno));
     return;
   }
 
+  bool is_running = (si.si_code == SI_USER);
   uintptr_t addr = reinterpret_cast<uintptr_t>(si.si_addr);
   addr &= ~0xfff;     // round to 4K page boundary
-  if (addr == 0) {    // null-pointer deref
+  if (!is_running && addr == 0) {    // null-pointer deref
     return;
   }
 
-  _LOG(log, scope_flags, "\nmemory map around fault addr %" PRIxPTR ":\n",
-       reinterpret_cast<uintptr_t>(si.si_addr));
+  _LOG(log, logtype::MAPS, "\nmemory map: %s\n", is_running? "" : "(fault address prefixed with --->)");
 
-  // Search for a match, or for a hole where the match would be.  The list
-  // is backward from the file content, so it starts at high addresses.
-  const backtrace_map_t* cur_map = NULL;
-  const backtrace_map_t* next_map = NULL;
-  const backtrace_map_t* prev_map = NULL;
-  for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
-    if (addr >= it->start && addr < it->end) {
-      cur_map = &*it;
-      if (it != map->begin()) {
-        prev_map = &*(it-1);
-      }
-      if (++it != map->end()) {
-        next_map = &*it;
-      }
-      break;
-    }
+  if(!is_running && (addr < map->begin()->start)) {
+    _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " before any mapped regions\n", addr);
   }
 
-  // Show the map address in ascending order (like /proc/pid/maps).
-  dump_map(log, prev_map, "map below", scope_flags);
-  dump_map(log, cur_map, "map for address", scope_flags);
-  dump_map(log, next_map, "map above", scope_flags);
+  BacktraceMap::const_iterator prev = map->begin();
+  for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
+    if (addr >= (*prev).end && addr < (*it).start) {
+      _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " between mapped regions\n", addr);
+    }
+    prev = it;
+    bool in_map = !is_running && (addr >= (*it).start) && (addr < (*it).end);
+    dump_map(log, &*it, in_map);
+  }
+  if (!is_running && (addr >= (*prev).end)) {
+    _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " after any mapped regions\n", addr);
+  }
 }
 
 static void dump_thread(
-    Backtrace* backtrace, log_t* log, int scope_flags, int* total_sleep_time_usec) {
+    Backtrace* backtrace, log_t* log, int* total_sleep_time_usec) {
+
   wait_for_stop(backtrace->Tid(), total_sleep_time_usec);
 
-  dump_registers(log, backtrace->Tid(), scope_flags);
-  dump_backtrace_and_stack(backtrace, log, scope_flags);
-  if (IS_AT_FAULT(scope_flags)) {
-    dump_memory_and_code(log, backtrace->Tid(), scope_flags);
-    dump_nearby_maps(backtrace->GetMap(), log, backtrace->Tid(), scope_flags);
-  }
+  dump_registers(log, backtrace->Tid());
+  dump_backtrace_and_stack(backtrace, log);
+
+  dump_memory_and_code(log, backtrace->Tid());
+  dump_nearby_maps(backtrace->GetMap(), log, backtrace->Tid());
 }
 
 // Return true if some thread is not detached cleanly
 static bool dump_sibling_thread_report(
     log_t* log, pid_t pid, pid_t tid, int* total_sleep_time_usec, BacktraceMap* map) {
   char task_path[64];
+
   snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
 
   DIR* d = opendir(task_path);
   // Bail early if the task directory cannot be opened
   if (d == NULL) {
-    XLOG("Cannot open /proc/%d/task\n", pid);
+    ALOGE("Cannot open /proc/%d/task\n", pid);
     return false;
   }
 
@@ -430,19 +414,23 @@
 
     // Skip this thread if cannot ptrace it
     if (ptrace(PTRACE_ATTACH, new_tid, 0, 0) < 0) {
+      _LOG(log, logtype::ERROR, "ptrace attach to %d failed: %s\n", new_tid, strerror(errno));
       continue;
     }
 
-    _LOG(log, 0, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
-    dump_thread_info(log, pid, new_tid, 0);
+    log->current_tid = new_tid;
+    _LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
+    dump_thread_info(log, pid, new_tid);
 
     UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, new_tid, map));
     if (backtrace->Unwind(0)) {
-      dump_thread(backtrace.get(), log, 0, total_sleep_time_usec);
+      dump_thread(backtrace.get(), log, total_sleep_time_usec);
     }
 
+    log->current_tid = log->crashed_tid;
+
     if (ptrace(PTRACE_DETACH, new_tid, 0, 0) != 0) {
-      LOG("ptrace detach from %d failed: %s\n", new_tid, strerror(errno));
+      _LOG(log, logtype::ERROR, "ptrace detach from %d failed: %s\n", new_tid, strerror(errno));
       detach_failed = true;
     }
   }
@@ -454,17 +442,19 @@
 // Reads the contents of the specified log device, filters out the entries
 // that don't match the specified pid, and writes them to the tombstone file.
 //
-// If "tail" is set, we only print the last few lines.
-static void dump_log_file(log_t* log, pid_t pid, const char* filename,
-  unsigned int tail) {
+// If "tail" is non-zero, log the last "tail" number of lines.
+static EventTagMap* g_eventTagMap = NULL;
+
+static void dump_log_file(
+    log_t* log, pid_t pid, const char* filename, unsigned int tail) {
   bool first = true;
-  struct logger_list *logger_list;
+  struct logger_list* logger_list;
 
   logger_list = android_logger_list_open(
-    android_name_to_log_id(filename), O_RDONLY | O_NONBLOCK, tail, pid);
+      android_name_to_log_id(filename), O_RDONLY | O_NONBLOCK, tail, pid);
 
   if (!logger_list) {
-    XLOG("Unable to open %s: %s\n", filename, strerror(errno));
+    ALOGE("Unable to open %s: %s\n", filename, strerror(errno));
     return;
   }
 
@@ -472,6 +462,7 @@
 
   while (true) {
     ssize_t actual = android_logger_list_read(logger_list, &log_entry);
+    struct logger_entry* entry;
 
     if (actual < 0) {
       if (actual == -EINTR) {
@@ -481,29 +472,25 @@
         // non-blocking EOF; we're done
         break;
       } else {
-        _LOG(log, 0, "Error while reading log: %s\n",
+        _LOG(log, logtype::ERROR, "Error while reading log: %s\n",
           strerror(-actual));
         break;
       }
     } else if (actual == 0) {
-      _LOG(log, 0, "Got zero bytes while reading log: %s\n",
+      _LOG(log, logtype::ERROR, "Got zero bytes while reading log: %s\n",
         strerror(errno));
       break;
     }
 
-    // NOTE: if you XLOG something here, this will spin forever,
+    // NOTE: if you ALOGV something here, this will spin forever,
     // because you will be writing as fast as you're reading.  Any
     // high-frequency debug diagnostics should just be written to
     // the tombstone file.
-    struct logger_entry* entry = &log_entry.entry_v1;
 
-    if (entry->pid != static_cast<int32_t>(pid)) {
-      // wrong pid, ignore
-      continue;
-    }
+    entry = &log_entry.entry_v1;
 
     if (first) {
-      _LOG(log, 0, "--------- %slog %s\n",
+      _LOG(log, logtype::LOGS, "--------- %slog %s\n",
         tail ? "tail end of " : "", filename);
       first = false;
     }
@@ -517,18 +504,7 @@
     if (!hdr_size) {
       hdr_size = sizeof(log_entry.entry_v1);
     }
-    char* msg = (char *)log_entry.buf + hdr_size;
-    unsigned char prio = msg[0];
-    char* tag = msg + 1;
-    msg = tag + strlen(tag) + 1;
-
-    // consume any trailing newlines
-    char* nl = msg + strlen(msg) - 1;
-    while (nl >= msg && *nl == '\n') {
-        *nl-- = '\0';
-    }
-
-    char prioChar = (prio < strlen(kPrioChars) ? kPrioChars[prio] : '?');
+    char* msg = reinterpret_cast<char*>(log_entry.buf) + hdr_size;
 
     char timeBuf[32];
     time_t sec = static_cast<time_t>(entry->sec);
@@ -537,6 +513,31 @@
     ptm = localtime_r(&sec, &tmBuf);
     strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
 
+    if (log_entry.id() == LOG_ID_EVENTS) {
+      if (!g_eventTagMap) {
+        g_eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+      }
+      AndroidLogEntry e;
+      char buf[512];
+      android_log_processBinaryLogBuffer(entry, &e, g_eventTagMap, buf, sizeof(buf));
+      _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8s: %s\n",
+         timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
+         'I', e.tag, e.message);
+      continue;
+    }
+
+    unsigned char prio = msg[0];
+    char* tag = msg + 1;
+    msg = tag + strlen(tag) + 1;
+
+    // consume any trailing newlines
+    char* nl = msg + strlen(msg) - 1;
+    while (nl >= msg && *nl == '\n') {
+      *nl-- = '\0';
+    }
+
+    char prioChar = (prio < strlen(kPrioChars) ? kPrioChars[prio] : '?');
+
     // Look for line breaks ('\n') and display each text line
     // on a separate line, prefixed with the header, like logcat does.
     do {
@@ -546,10 +547,9 @@
         ++nl;
       }
 
-      _LOG(log, 0, "%s.%03d %5d %5d %c %-8s: %s\n",
+      _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8s: %s\n",
          timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
          prioChar, tag, msg);
-
     } while ((msg = nl));
   }
 
@@ -558,7 +558,7 @@
 
 // Dumps the logs generated by the specified pid to the tombstone, from both
 // "system" and "main" log devices.  Ideally we'd interleave the output.
-static void dump_logs(log_t* log, pid_t pid, unsigned tail) {
+static void dump_logs(log_t* log, pid_t pid, unsigned int tail) {
   dump_log_file(log, pid, "system", tail);
   dump_log_file(log, pid, "main", tail);
 }
@@ -574,33 +574,25 @@
   memset(msg, 0, sizeof(msg));
   char* p = &msg[0];
   while (p < &msg[sizeof(msg)]) {
-    uint32_t data;
+    word_t data;
+    size_t len = sizeof(word_t);
     if (!backtrace->ReadWord(address, &data)) {
       break;
     }
-    address += sizeof(uint32_t);
+    address += sizeof(word_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;
-    }
+    while (len > 0 && (*p++ = (data >> (sizeof(word_t) - len) * 8) & 0xff) != 0)
+       len--;
   }
   msg[sizeof(msg) - 1] = '\0';
 
-  _LOG(log, SCOPE_AT_FAULT, "Abort message: '%s'\n", msg);
+  _LOG(log, logtype::HEADER, "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, uintptr_t abort_msg_address,
-                       bool dump_sibling_threads, int* total_sleep_time_usec) {
+static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, int si_code,
+                       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");
@@ -616,20 +608,20 @@
     TEMP_FAILURE_RETRY( write(log->amfd, &datum, 4) );
   }
 
-  _LOG(log, SCOPE_AT_FAULT,
+  _LOG(log, logtype::HEADER,
        "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
-  dump_build_info(log);
-  dump_revision_info(log);
-  dump_thread_info(log, pid, tid, SCOPE_AT_FAULT);
+  dump_header_info(log);
+  dump_thread_info(log, pid, tid);
+
   if (signal) {
-    dump_fault_addr(log, tid, signal);
+    dump_signal_info(log, tid, signal, si_code);
   }
 
   UniquePtr<BacktraceMap> map(BacktraceMap::Create(pid));
   UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
   if (backtrace->Unwind(0)) {
     dump_abort_message(backtrace.get(), log, abort_msg_address);
-    dump_thread(backtrace.get(), log, SCOPE_AT_FAULT, total_sleep_time_usec);
+    dump_thread(backtrace.get(), log, total_sleep_time_usec);
   }
 
   if (want_logs) {
@@ -663,24 +655,19 @@
 //
 // Returns the path of the tombstone file, allocated using malloc().  Caller must free() it.
 static char* find_and_open_tombstone(int* fd) {
-  unsigned long mtime = ULONG_MAX;
-  struct stat sb;
-
-  // XXX: Our stat.st_mtime isn't time_t. If it changes, as it probably ought
-  // to, our logic breaks. This check will generate a warning if that happens.
-  typecheck(mtime, sb.st_mtime);
-
-  // In a single wolf-like pass, find an available slot and, in case none
+  // In a single pass, find an available slot and, in case none
   // exist, find and record the least-recently-modified file.
   char path[128];
-  int oldest = 0;
+  int oldest = -1;
+  struct stat oldest_sb;
   for (int i = 0; i < MAX_TOMBSTONES; i++) {
-    snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", i);
+    snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, i);
 
+    struct stat sb;
     if (!stat(path, &sb)) {
-      if (sb.st_mtime < mtime) {
+      if (oldest < 0 || sb.st_mtime < oldest_sb.st_mtime) {
         oldest = i;
-        mtime = sb.st_mtime;
+        oldest_sb.st_mtime = sb.st_mtime;
       }
       continue;
     }
@@ -695,11 +682,16 @@
     return strdup(path);
   }
 
+  if (oldest < 0) {
+    ALOGE("Failed to find a valid tombstone, default to using tombstone 0.\n");
+    oldest = 0;
+  }
+
   // we didn't find an available file, so we clobber the oldest one
-  snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", oldest);
+  snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, oldest);
   *fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
   if (*fd < 0) {
-    LOG("failed to open tombstone file '%s': %s\n", path, strerror(errno));
+    ALOGE("failed to open tombstone file '%s': %s\n", path, strerror(errno));
     return NULL;
   }
   fchown(*fd, AID_SYSTEM, AID_SYSTEM);
@@ -736,35 +728,45 @@
   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);
-  chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM);
+char* engrave_tombstone(pid_t pid, pid_t tid, int signal, int original_si_code,
+                        uintptr_t abort_msg_address, bool dump_sibling_threads,
+                        bool* detach_failed, int* total_sleep_time_usec) {
+
+  log_t log;
+  log.current_tid = tid;
+  log.crashed_tid = tid;
+
+  if ((mkdir(TOMBSTONE_DIR, 0755) == -1) && (errno != EEXIST)) {
+    _LOG(&log, logtype::ERROR, "failed to create %s: %s\n", TOMBSTONE_DIR, strerror(errno));
+  }
+
+  if (chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM) == -1) {
+    _LOG(&log, logtype::ERROR, "failed to change ownership of %s: %s\n", TOMBSTONE_DIR, strerror(errno));
+  }
 
   int fd = -1;
   char* path = NULL;
-  if (selinux_android_restorecon(TOMBSTONE_DIR) == 0) {
+  if (selinux_android_restorecon(TOMBSTONE_DIR, 0) == 0) {
     path = find_and_open_tombstone(&fd);
   } else {
-    LOG("Failed to restore security context, not writing tombstone.\n");
+    _LOG(&log, logtype::ERROR, "Failed to restore security context, not writing tombstone.\n");
   }
 
-  if (fd < 0 && quiet) {
-    LOG("Skipping tombstone write, nothing to do.\n");
+  if (fd < 0) {
+    _LOG(&log, logtype::ERROR, "Skipping tombstone write, nothing to do.\n");
     *detach_failed = false;
     return NULL;
   }
 
-  log_t log;
   log.tfd = fd;
   // Preserve amfd since it can be modified through the calls below without
   // being closed.
   int amfd = activity_manager_connect();
   log.amfd = amfd;
-  log.quiet = quiet;
-  *detach_failed = dump_crash(
-      &log, pid, tid, signal, abort_msg_address, dump_sibling_threads, total_sleep_time_usec);
+  *detach_failed = dump_crash(&log, pid, tid, signal, original_si_code, abort_msg_address,
+                              dump_sibling_threads, total_sleep_time_usec);
+
+  ALOGI("\nTombstone written to: %s\n", path);
 
   // Either of these file descriptors can be -1, any error is ignored.
   close(amfd);
diff --git a/debuggerd/tombstone.h b/debuggerd/tombstone.h
index e9878bf..7e2b2fe 100644
--- a/debuggerd/tombstone.h
+++ b/debuggerd/tombstone.h
@@ -23,7 +23,9 @@
 
 /* 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, uintptr_t abort_msg_address,
-        bool dump_sibling_threads, bool quiet, bool* detach_failed, int* total_sleep_time_usec);
+char* engrave_tombstone(pid_t pid, pid_t tid, int signal, int original_si_code,
+                        uintptr_t abort_msg_address,
+                        bool dump_sibling_threads, bool* detach_failed,
+                        int* total_sleep_time_usec);
 
 #endif // _DEBUGGERD_TOMBSTONE_H
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index 35f061e..a163344 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -14,30 +14,30 @@
  * limitations under the License.
  */
 
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <signal.h>
-#include <log/logd.h>
-#include <sys/ptrace.h>
-#include <sys/wait.h>
-#include <arpa/inet.h>
-#include <assert.h>
+#define LOG_TAG "DEBUG"
 
 #include "utility.h"
 
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+
+#include <backtrace/Backtrace.h>
+#include <log/log.h>
+
 const int sleep_time_usec = 50000;         // 0.05 seconds
 const int max_total_sleep_usec = 10000000; // 10 seconds
 
 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) );
+    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));
+      ALOGE("AM write failure (%d / %s)\n", errno, strerror(errno));
       return -1;
     }
     to_write -= written;
@@ -45,35 +45,41 @@
   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;
+// Whitelist output desired in the logcat output.
+bool is_allowed_in_logcat(enum logtype ltype) {
+  if ((ltype == ERROR)
+   || (ltype == HEADER)
+   || (ltype == REGISTERS)
+   || (ltype == BACKTRACE)) {
+    return true;
+  }
+  return false;
+}
 
+void _LOG(log_t* log, enum logtype ltype, const char* fmt, ...) {
+  bool write_to_tombstone = (log->tfd != -1);
+  bool write_to_logcat = is_allowed_in_logcat(ltype)
+                      && (log->crashed_tid == log->current_tid);
+  bool write_to_activitymanager = (log->amfd != -1);
+
+  char buf[512];
   va_list ap;
   va_start(ap, fmt);
+  vsnprintf(buf, sizeof(buf), fmt, ap);
+  va_end(ap);
 
-  // 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);
+  size_t len = strlen(buf);
+  if (len <= 0) {
+    return;
   }
 
-  if (want_tfd_write) {
-    write(log->tfd, buf, len);
+  if (write_to_tombstone) {
+    TEMP_FAILURE_RETRY(write(log->tfd, buf, len));
   }
 
-  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) {
+  if (write_to_logcat) {
+    __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_INFO, LOG_TAG, buf);
+    if (write_to_activitymanager) {
       int written = write_to_am(log->amfd, buf, len);
       if (written <= 0) {
         // timeout or other failure on write; stop informing the activity manager
@@ -81,7 +87,6 @@
       }
     }
   }
-  va_end(ap);
 }
 
 int wait_for_signal(pid_t tid, int* total_sleep_time_usec) {
@@ -91,25 +96,25 @@
     if (n < 0) {
       if (errno == EAGAIN)
         continue;
-      LOG("waitpid failed: %s\n", strerror(errno));
+      ALOGE("waitpid failed: %s\n", strerror(errno));
       return -1;
     } else if (n > 0) {
-      XLOG("waitpid: n=%d status=%08x\n", n, status);
+      ALOGV("waitpid: n=%d status=%08x\n", n, status);
       if (WIFSTOPPED(status)) {
         return WSTOPSIG(status);
       } else {
-        LOG("unexpected waitpid response: n=%d, status=%08x\n", n, status);
+        ALOGE("unexpected waitpid response: n=%d, status=%08x\n", n, status);
         return -1;
       }
     }
 
     if (*total_sleep_time_usec > max_total_sleep_usec) {
-      LOG("timed out waiting for tid=%d to die\n", tid);
+      ALOGE("timed out waiting for tid=%d to die\n", tid);
       return -1;
     }
 
     // not ready yet
-    XLOG("not ready yet\n");
+    ALOGV("not ready yet\n");
     usleep(sleep_time_usec);
     *total_sleep_time_usec += sleep_time_usec;
   }
@@ -119,7 +124,7 @@
   siginfo_t si;
   while (TEMP_FAILURE_RETRY(ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) < 0 && errno == ESRCH) {
     if (*total_sleep_time_usec > max_total_sleep_usec) {
-      LOG("timed out waiting for tid=%d to stop\n", tid);
+      ALOGE("timed out waiting for tid=%d to stop\n", tid);
       break;
     }
 
@@ -127,3 +132,77 @@
     *total_sleep_time_usec += sleep_time_usec;
   }
 }
+
+#if defined (__mips__)
+#define DUMP_MEMORY_AS_ASCII 1
+#else
+#define DUMP_MEMORY_AS_ASCII 0
+#endif
+
+void dump_memory(log_t* log, pid_t tid, uintptr_t addr) {
+    char code_buffer[64];
+    char ascii_buffer[32];
+    uintptr_t p, end;
+
+    p = addr & ~(sizeof(long) - 1);
+    /* Dump 32 bytes before addr */
+    p -= 32;
+    if (p > addr) {
+        /* catch underflow */
+        p = 0;
+    }
+    /* Dump 256 bytes */
+    end = p + 256;
+    /* catch overflow; 'end - p' has to be multiples of 16 */
+    while (end < p) {
+        end -= 16;
+    }
+
+    /* Dump the code around PC as:
+     *  addr             contents                           ascii
+     *  0000000000008d34 ef000000e8bd0090 e1b00000512fff1e  ............../Q
+     *  0000000000008d44 ea00b1f9e92d0090 e3a070fcef000000  ......-..p......
+     * On 32-bit machines, there are still 16 bytes per line but addresses and
+     * words are of course presented differently.
+     */
+    while (p < end) {
+        char* asc_out = ascii_buffer;
+
+        int len = snprintf(code_buffer, sizeof(code_buffer), "%" PRIPTR " ", p);
+
+        for (size_t i = 0; i < 16/sizeof(long); i++) {
+            long data = ptrace(PTRACE_PEEKTEXT, tid, (void*)p, NULL);
+            if (data == -1 && errno != 0) {
+                // ptrace failed, probably because we're dumping memory in an
+                // unmapped or inaccessible page.
+#ifdef __LP64__
+                len += sprintf(code_buffer + len, "---------------- ");
+#else
+                len += sprintf(code_buffer + len, "-------- ");
+#endif
+            } else {
+                len += sprintf(code_buffer + len, "%" PRIPTR " ",
+                               static_cast<uintptr_t>(data));
+            }
+
+#if DUMP_MEMORY_AS_ASCII
+            for (size_t j = 0; j < sizeof(long); j++) {
+                /*
+                 * Our isprint() allows high-ASCII characters that display
+                 * differently (often badly) in different viewers, so we
+                 * just use a simpler test.
+                 */
+                char val = (data >> (j*8)) & 0xff;
+                if (val >= 0x20 && val < 0x7f) {
+                    *asc_out++ = val;
+                } else {
+                    *asc_out++ = '.';
+                }
+            }
+#endif
+            p += sizeof(long);
+        }
+        *asc_out = '\0';
+        _LOG(log, logtype::MEMORY, "    %s %s\n", code_buffer, ascii_buffer);
+    }
+}
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index 1f006ed..f2e2d29 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -18,49 +18,56 @@
 #ifndef _DEBUGGERD_UTILITY_H
 #define _DEBUGGERD_UTILITY_H
 
-#include <stddef.h>
 #include <stdbool.h>
+#include <sys/types.h>
+
+// Figure out the abi based on defined macros.
+#if defined(__arm__)
+#define ABI_STRING "arm"
+#elif defined(__aarch64__)
+#define ABI_STRING "arm64"
+#elif defined(__mips__)
+#define ABI_STRING "mips"
+#elif defined(__i386__)
+#define ABI_STRING "x86"
+#elif defined(__x86_64__)
+#define ABI_STRING "x86_64"
+#else
+#error "Unsupported ABI"
+#endif
+
 
 typedef struct {
     /* tombstone file descriptor */
     int tfd;
     /* Activity Manager socket file descriptor */
     int amfd;
-    /* if true, does not log anything to the Android logcat or Activity Manager */
-    bool quiet;
+    // The tid of the thread that crashed.
+    pid_t crashed_tid;
+    // The tid of the thread we are currently working with.
+    pid_t current_tid;
 } log_t;
 
-/* Log information onto the tombstone.  scopeFlags is a bitmask of the flags defined
- * here. */
-void _LOG(log_t* log, int scopeFlags, const char *fmt, ...)
+// List of types of logs to simplify the logging decision in _LOG
+enum logtype {
+  ERROR,
+  HEADER,
+  THREAD,
+  REGISTERS,
+  BACKTRACE,
+  MAPS,
+  MEMORY,
+  STACK,
+  LOGS
+};
+
+/* Log information onto the tombstone. */
+void _LOG(log_t* log, logtype ltype, const char *fmt, ...)
         __attribute__ ((format(printf, 3, 4)));
 
-/* 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, 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, SCOPE_AT_FAULT, fmt)
-#else
-#define XLOG2(fmt...) do {} while(0)
-#endif
-
 int wait_for_signal(pid_t tid, int* total_sleep_time_usec);
 void wait_for_stop(pid_t tid, int* total_sleep_time_usec);
 
+void dump_memory(log_t* log, pid_t tid, uintptr_t addr);
+
 #endif // _DEBUGGERD_UTILITY_H
diff --git a/debuggerd/vfp-crasher.c b/debuggerd/vfp-crasher.c
deleted file mode 100644
index 7a19cdd..0000000
--- a/debuggerd/vfp-crasher.c
+++ /dev/null
@@ -1,7 +0,0 @@
-int main()
-{
-  extern void crash(void);
-
-  crash();
-  return 0;
-}
diff --git a/debuggerd/vfp.S b/debuggerd/vfp.S
deleted file mode 100644
index 9744f6f..0000000
--- a/debuggerd/vfp.S
+++ /dev/null
@@ -1,43 +0,0 @@
-    .text
-    .align 2
-    .global crash
-    .type crash, %function
-crash:
-    fconstd   d0, #0
-    fconstd   d1, #1
-    fconstd   d2, #2
-    fconstd   d3, #3
-    fconstd   d4, #4
-    fconstd   d5, #5
-    fconstd   d6, #6
-    fconstd   d7, #7
-    fconstd   d8, #8
-    fconstd   d9, #9
-    fconstd   d10, #10
-    fconstd   d11, #11
-    fconstd   d12, #12
-    fconstd   d13, #13
-    fconstd   d14, #14
-    fconstd   d15, #15
-#ifdef WITH_VFP_D32
-    fconstd   d16, #16
-    fconstd   d17, #17
-    fconstd   d18, #18
-    fconstd   d19, #19
-    fconstd   d20, #20
-    fconstd   d21, #21
-    fconstd   d22, #22
-    fconstd   d23, #23
-    fconstd   d24, #24
-    fconstd   d25, #25
-    fconstd   d26, #26
-    fconstd   d27, #27
-    fconstd   d28, #28
-    fconstd   d29, #29
-    fconstd   d30, #30
-    fconstd   d31, #31
-#endif
-    mov       r0, #0
-    str       r0, [r0]
-    bx        lr
-
diff --git a/debuggerd/x86/machine.cpp b/debuggerd/x86/machine.cpp
index 141f19a..57330c1 100644
--- a/debuggerd/x86/machine.cpp
+++ b/debuggerd/x86/machine.cpp
@@ -25,21 +25,21 @@
 #include "../utility.h"
 #include "../machine.h"
 
-void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
+void dump_memory_and_code(log_t*, pid_t) {
 }
 
-void dump_registers(log_t* log, pid_t tid, int scope_flags) {
+void dump_registers(log_t* log, pid_t tid) {
   struct pt_regs r;
   if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
-    _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
     return;
   }
-  _LOG(log, scope_flags, "    eax %08lx  ebx %08lx  ecx %08lx  edx %08lx\n",
+  _LOG(log, logtype::REGISTERS, "    eax %08lx  ebx %08lx  ecx %08lx  edx %08lx\n",
        r.eax, r.ebx, r.ecx, r.edx);
-  _LOG(log, scope_flags, "    esi %08lx  edi %08lx\n",
+  _LOG(log, logtype::REGISTERS, "    esi %08lx  edi %08lx\n",
        r.esi, r.edi);
-  _LOG(log, scope_flags, "    xcs %08x  xds %08x  xes %08x  xfs %08x  xss %08x\n",
+  _LOG(log, logtype::REGISTERS, "    xcs %08x  xds %08x  xes %08x  xfs %08x  xss %08x\n",
        r.xcs, r.xds, r.xes, r.xfs, r.xss);
-  _LOG(log, scope_flags, "    eip %08lx  ebp %08lx  esp %08lx  flags %08lx\n",
+  _LOG(log, logtype::REGISTERS, "    eip %08lx  ebp %08lx  esp %08lx  flags %08lx\n",
        r.eip, r.ebp, r.esp, r.eflags);
 }
diff --git a/debuggerd/x86_64/crashglue.S b/debuggerd/x86_64/crashglue.S
new file mode 100644
index 0000000..4d2a5c0
--- /dev/null
+++ b/debuggerd/x86_64/crashglue.S
@@ -0,0 +1,15 @@
+.globl crash1
+.globl crashnostack
+
+crash1:
+	movl $0xa5a50000, %eax
+	movl $0xa5a50001, %ebx
+	movl $0xa5a50002, %ecx
+
+	movl $0, %edx
+	jmp *%rdx
+
+
+crashnostack:
+	movl $0, %ebp
+	jmp *%rbp
diff --git a/debuggerd/x86_64/machine.cpp b/debuggerd/x86_64/machine.cpp
new file mode 100755
index 0000000..af4f35a
--- /dev/null
+++ b/debuggerd/x86_64/machine.cpp
@@ -0,0 +1,51 @@
+/*
+** 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.
+*/
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/user.h>
+
+#include "../utility.h"
+#include "../machine.h"
+
+void dump_memory_and_code(log_t*, pid_t) {
+}
+
+void dump_registers(log_t* log, pid_t tid) {
+    struct user_regs_struct r;
+    if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
+        _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
+        return;
+    }
+    _LOG(log, logtype::REGISTERS, "    rax %016lx  rbx %016lx  rcx %016lx  rdx %016lx\n",
+         r.rax, r.rbx, r.rcx, r.rdx);
+    _LOG(log, logtype::REGISTERS, "    rsi %016lx  rdi %016lx\n",
+         r.rsi, r.rdi);
+    _LOG(log, logtype::REGISTERS, "    r8  %016lx  r9  %016lx  r10 %016lx  r11 %016lx\n",
+         r.r8, r.r9, r.r10, r.r11);
+    _LOG(log, logtype::REGISTERS, "    r12 %016lx  r13 %016lx  r14 %016lx  r15 %016lx\n",
+         r.r12, r.r13, r.r14, r.r15);
+    _LOG(log, logtype::REGISTERS, "    cs  %016lx  ss  %016lx\n",
+         r.cs, r.ss);
+    _LOG(log, logtype::REGISTERS, "    rip %016lx  rbp %016lx  rsp %016lx  eflags %016lx\n",
+         r.rip, r.rbp, r.rsp, r.eflags);
+}
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 05ddf2a..73794a0 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c util.c fs.c
 LOCAL_MODULE := fastboot
 LOCAL_MODULE_TAGS := debug
-LOCAL_CFLAGS += -std=gnu99
+LOCAL_CFLAGS += -std=gnu99 -Werror
 
 ifeq ($(HOST_OS),linux)
   LOCAL_SRC_FILES += usb_linux.c util_linux.c
@@ -72,6 +72,7 @@
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := usbtest.c usb_linux.c util.c
 LOCAL_MODULE := usbtest
+LOCAL_CFLAGS := -Werror
 include $(BUILD_HOST_EXECUTABLE)
 endif
 
diff --git a/fastboot/engine.c b/fastboot/engine.c
index 0fab703..2f90e41 100644
--- a/fastboot/engine.c
+++ b/fastboot/engine.c
@@ -30,10 +30,10 @@
 #include "fs.h"
 
 #include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <stdarg.h>
 #include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -45,6 +45,10 @@
 #include <sys/mman.h>
 #endif
 
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
+
 #define ARRAY_SIZE(x)           (sizeof(x)/sizeof(x[0]))
 
 #define OP_DOWNLOAD   1
@@ -102,18 +106,19 @@
  * Not all devices report the filesystem type, so don't report any errors,
  * just return false.
  */
-int fb_format_supported(usb_handle *usb, const char *partition)
+int fb_format_supported(usb_handle *usb, const char *partition, const char *type_override)
 {
-    char response[FB_RESPONSE_SZ + 1] = {0,};
+    char fs_type[FB_RESPONSE_SZ + 1] = {0,};
     int status;
-    unsigned int i;
 
-    status = fb_getvar(usb, response, "partition-type:%s", partition);
+    if (type_override) {
+        return !!fs_get_generator(type_override);
+    }
+    status = fb_getvar(usb, fs_type, "partition-type:%s", partition);
     if (status) {
         return 0;
     }
-
-    return !!fs_get_generator(response);
+    return !!fs_get_generator(fs_type);
 }
 
 static int cb_default(Action *a, int status, char *resp)
@@ -195,9 +200,7 @@
 
 static int match(char *str, const char **value, unsigned count)
 {
-    const char *val;
     unsigned n;
-    int len;
 
     for (n = 0; n < count; n++) {
         const char *val = value[n];
@@ -323,7 +326,7 @@
     a->func = cb_save;
 }
 
-static int cb_do_nothing(Action *a, int status, char *resp)
+static int cb_do_nothing(Action *a __unused, int status __unused, char *resp __unused)
 {
     fprintf(stderr,"\n");
     return 0;
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index 4fd1a8e..266d0b5 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -28,21 +28,21 @@
 
 #define _LARGEFILE64_SOURCE
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <string.h>
+#include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <unistd.h>
-#include <limits.h>
-#include <ctype.h>
 #include <getopt.h>
-
+#include <inttypes.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/types.h>
-#include <sys/stat.h>
+#include <unistd.h>
 
 #include <bootimg.h>
 #include <sparse/sparse.h>
@@ -71,7 +71,6 @@
 static const char *serial = 0;
 static const char *product = 0;
 static const char *cmdline = 0;
-static int wipe_data = 0;
 static unsigned short vendor_id = 0;
 static int long_listing = 0;
 static int64_t sparse_limit = -1;
@@ -100,10 +99,11 @@
     char sig_name[13];
     char part_name[9];
     bool is_optional;
-} images[3] = {
+} images[4] = {
     {"boot.img", "boot.sig", "boot", false},
     {"recovery.img", "recovery.sig", "recovery", true},
     {"system.img", "system.sig", "system", false},
+    {"tos.img", "tos.sig", "tos", true},
 };
 
 void get_my_path(char *path);
@@ -120,6 +120,8 @@
         fn = "recovery.img";
     } else if(!strcmp(item,"system")) {
         fn = "system.img";
+    } else if(!strcmp(item,"tos")) {
+        fn = "tos.img";
     } else if(!strcmp(item,"userdata")) {
         fn = "userdata.img";
     } else if(!strcmp(item,"cache")) {
@@ -266,7 +268,7 @@
             announce = 0;
             fprintf(stderr,"< waiting for device >\n");
         }
-        sleep(1);
+        usleep(1000);
     }
 }
 
@@ -285,10 +287,13 @@
             "\n"
             "commands:\n"
             "  update <filename>                        reflash device from update.zip\n"
-            "  flashall                                 flash boot + recovery + system\n"
+            "  flashall                                 flash boot, system, and if found,\n"
+            "                                           recovery, tos\n"
             "  flash <partition> [ <filename> ]         write a file to a flash partition\n"
             "  erase <partition>                        erase a flash partition\n"
-            "  format <partition>                       format a flash partition \n"
+            "  format[:[<fs type>][:[<size>]] <partition> format a flash partition.\n"
+            "                                           Can override the fs type and/or\n"
+            "                                           size the bootloader reports.\n"
             "  getvar <variable>                        display a bootloader variable\n"
             "  boot <kernel> [ <ramdisk> ]              download and boot kernel\n"
             "  flash:raw boot <kernel> [ <ramdisk> ]    create bootimage and flash it\n"
@@ -309,10 +314,12 @@
             "  -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. 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"
+            "  -b <base_addr>                           specify a custom kernel base address.\n"
+            "                                           default: 0x10000000\n"
+            "  -n <page size>                           specify the nand page size.\n"
+            "                                           default: 2048\n"
+            "  -S <size>[K|M|G]                         automatically sparse files greater\n"
+            "                                           than size.  0 to disable\n"
         );
 }
 
@@ -419,7 +426,7 @@
         return -1;
     }
 
-    if (write(fd, data, sz) != sz) {
+    if (write(fd, data, sz) != (ssize_t)sz) {
         fd = -1;
     }
 
@@ -570,7 +577,7 @@
     if (!status) {
         limit = strtoul(response, NULL, 0);
         if (limit > 0) {
-            fprintf(stderr, "target reported max download size of %lld bytes\n",
+            fprintf(stderr, "target reported max download size of %" PRId64 " bytes\n",
                     limit);
         }
     }
@@ -613,7 +620,7 @@
     /* The function fb_format_supported() currently returns the value
      * we want, so just call it.
      */
-     return fb_format_supported(usb, part);
+     return fb_format_supported(usb, part, NULL);
 }
 
 static int load_buf_fd(usb_handle *usb, int fd,
@@ -657,7 +664,7 @@
 
     fd = open(fname, O_RDONLY | O_BINARY);
     if (fd < 0) {
-        die("cannot open '%s'\n", fname);
+        return -1;
     }
 
     return load_buf_fd(usb, fd, buf);
@@ -713,7 +720,7 @@
     int fd;
     int rc;
     struct fastboot_buffer buf;
-    int i;
+    size_t i;
 
     queue_info_dump();
 
@@ -787,7 +794,7 @@
     void *data;
     unsigned sz;
     struct fastboot_buffer buf;
-    int i;
+    size_t i;
 
     queue_info_dump();
 
@@ -819,7 +826,6 @@
 
 int do_oem_command(int argc, char **argv)
 {
-    int i;
     char command[256];
     if (argc <= 1) return 0;
 
@@ -876,9 +882,12 @@
     return num;
 }
 
-void fb_perform_format(const char *partition, int skip_if_not_supported)
+void fb_perform_format(const char *partition, int skip_if_not_supported,
+                       const char *type_override, const char *size_override)
 {
-    char pType[FB_RESPONSE_SZ + 1], pSize[FB_RESPONSE_SZ + 1];
+    char pTypeBuff[FB_RESPONSE_SZ + 1], pSizeBuff[FB_RESPONSE_SZ + 1];
+    char *pType = pTypeBuff;
+    char *pSize = pSizeBuff;
     unsigned int limit = INT_MAX;
     struct fastboot_buffer buf;
     const char *errMsg = NULL;
@@ -897,12 +906,28 @@
         errMsg = "Can't determine partition type.\n";
         goto failed;
     }
+    if (type_override) {
+        if (strcmp(type_override, pType)) {
+            fprintf(stderr,
+                    "Warning: %s type is %s, but %s was requested for formating.\n",
+                    partition, pType, type_override);
+        }
+        pType = (char *)type_override;
+    }
 
     status = fb_getvar(usb, pSize, "partition-size:%s", partition);
     if (status) {
         errMsg = "Unable to get partition size\n";
         goto failed;
     }
+    if (size_override) {
+        if (strcmp(size_override, pSize)) {
+            fprintf(stderr,
+                    "Warning: %s size is %s, but %s was requested for formating.\n",
+                    partition, pSize, size_override);
+        }
+        pSize = (char *)size_override;
+    }
 
     gen = fs_get_generator(pType);
     if (!gen) {
@@ -953,13 +978,13 @@
     unsigned sz;
     int status;
     int c;
-    int r;
 
     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'},
+        {"tags_offset", required_argument, 0, 't'},
         {"help", 0, 0, 'h'},
         {0, 0, 0, 0}
     };
@@ -967,8 +992,7 @@
     serial = getenv("ANDROID_SERIAL");
 
     while (1) {
-        int option_index = 0;
-        c = getopt_long(argc, argv, "wub:k:n:r:s:S:lp:c:i:m:h", longopts, NULL);
+        c = getopt_long(argc, argv, "wub:k:n:r:t:s:S:lp:c:i:m:h", longopts, NULL);
         if (c < 0) {
             break;
         }
@@ -1009,6 +1033,9 @@
         case 'r':
             ramdisk_offset = strtoul(optarg, 0, 16);
             break;
+        case 't':
+            tags_offset = strtoul(optarg, 0, 16);
+            break;
         case 's':
             serial = optarg;
             break;
@@ -1060,18 +1087,42 @@
         } else if(!strcmp(*argv, "erase")) {
             require(2);
 
-            if (fb_format_supported(usb, argv[1])) {
+            if (fb_format_supported(usb, argv[1], NULL)) {
                 fprintf(stderr, "******** Did you mean to fastboot format this partition?\n");
             }
 
             fb_queue_erase(argv[1]);
             skip(2);
-        } else if(!strcmp(*argv, "format")) {
+        } else if(!strncmp(*argv, "format", strlen("format"))) {
+            char *overrides;
+            char *type_override = NULL;
+            char *size_override = NULL;
             require(2);
+            /*
+             * Parsing for: "format[:[type][:[size]]]"
+             * Some valid things:
+             *  - select ontly the size, and leave default fs type:
+             *    format::0x4000000 userdata
+             *  - default fs type and size:
+             *    format userdata
+             *    format:: userdata
+             */
+            overrides = strchr(*argv, ':');
+            if (overrides) {
+                overrides++;
+                size_override = strchr(overrides, ':');
+                if (size_override) {
+                    size_override[0] = '\0';
+                    size_override++;
+                }
+                type_override = overrides;
+            }
+            if (type_override && !type_override[0]) type_override = NULL;
+            if (size_override && !size_override[0]) size_override = NULL;
             if (erase_first && needs_erase(argv[1])) {
                 fb_queue_erase(argv[1]);
             }
-            fb_perform_format(argv[1], 0);
+            fb_perform_format(argv[1], 0, type_override, size_override);
             skip(2);
         } else if(!strcmp(*argv, "signature")) {
             require(2);
@@ -1159,12 +1210,13 @@
 
     if (wants_wipe) {
         fb_queue_erase("userdata");
-        fb_perform_format("userdata", 1);
+        fb_perform_format("userdata", 1, NULL, NULL);
         fb_queue_erase("cache");
-        fb_perform_format("cache", 1);
+        fb_perform_format("cache", 1, NULL, NULL);
     }
     if (wants_reboot) {
         fb_queue_reboot();
+        fb_queue_wait_for_disconnect();
     } else if (wants_reboot_bootloader) {
         fb_queue_command("reboot-bootloader", "rebooting into bootloader");
         fb_queue_wait_for_disconnect();
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index c510a36..fc5d4f4 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -45,7 +45,7 @@
 
 /* engine.c - high level command queue engine */
 int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...);
-int fb_format_supported(usb_handle *usb, const char *partition);
+int fb_format_supported(usb_handle *usb, const char *partition, const char *type_override);
 void fb_queue_flash(const char *ptn, void *data, unsigned sz);
 void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, unsigned sz);
 void fb_queue_erase(const char *ptn);
diff --git a/fastboot/fs.c b/fastboot/fs.c
index 6a1f9e6..cd4b880 100644
--- a/fastboot/fs.c
+++ b/fastboot/fs.c
@@ -39,12 +39,12 @@
 
 };
 
-const struct fs_generator* fs_get_generator(const char* name)
+const struct fs_generator* fs_get_generator(const char *fs_type)
 {
     unsigned i;
 
     for (i = 0; i < sizeof(generators) / sizeof(*generators); i++)
-        if (!strcmp(generators[i].fs_type, name))
+        if (!strcmp(generators[i].fs_type, fs_type))
             return generators + i;
 
     return NULL;
diff --git a/fastboot/fs.h b/fastboot/fs.h
index 65b9555..8444081 100644
--- a/fastboot/fs.h
+++ b/fastboot/fs.h
@@ -1,11 +1,11 @@
 #ifndef _FS_H_
-#define _FH_H_
+#define _FS_H_
 
 #include <stdint.h>
 
 struct fs_generator;
 
-const struct fs_generator* fs_get_generator(const char* name);
+const struct fs_generator* fs_get_generator(const char *fs_type);
 int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize);
 
 #endif
diff --git a/fastboot/protocol.c b/fastboot/protocol.c
index a0e0fd4..84e9837 100644
--- a/fastboot/protocol.c
+++ b/fastboot/protocol.c
@@ -110,7 +110,6 @@
                           char *response)
 {
     int cmdsize = strlen(cmd);
-    int r;
 
     if(response) {
         response[0] = 0;
@@ -189,8 +188,6 @@
 static int _command_send_no_data(usb_handle *usb, const char *cmd,
                                  char *response)
 {
-    int r;
-
     return _command_start(usb, cmd, 0, response);
 }
 
diff --git a/fastboot/usb_linux.c b/fastboot/usb_linux.c
index f2ce226..a45f9f8 100644
--- a/fastboot/usb_linux.c
+++ b/fastboot/usb_linux.c
@@ -125,9 +125,6 @@
     unsigned i;
     unsigned e;
     
-    struct stat st;
-    int result;
-
     if(check(ptr, len, USB_DT_DEVICE, USB_DT_DEVICE_SIZE))
         return -1;
     dev = (void*) ptr;
diff --git a/fastboot/usb_windows.c b/fastboot/usb_windows.c
index 07f7be2..0d13863 100644
--- a/fastboot/usb_windows.c
+++ b/fastboot/usb_windows.c
@@ -152,7 +152,7 @@
 }
 
 int usb_write(usb_handle* handle, const void* data, int len) {
-    unsigned long time_out = 500 + len * 8;
+    unsigned long time_out = 5000;
     unsigned long written = 0;
     unsigned count = 0;
     int ret;
@@ -178,7 +178,7 @@
 
             count += written;
             len -= written;
-            data += written;
+            data = (const char *)data + written;
 
             if (len == 0)
                 return count;
@@ -194,7 +194,7 @@
 }
 
 int usb_read(usb_handle *handle, void* data, int len) {
-    unsigned long time_out = 500 + len * 8;
+    unsigned long time_out = 0;
     unsigned long read = 0;
     int ret;
 
@@ -212,7 +212,7 @@
             DBG("usb_read got: %ld, expected: %d, errno: %d\n", read, xfer, errno);
             if (ret) {
                 return read;
-            } else if (errno != ERROR_SEM_TIMEOUT) {
+            } else {
                 // assume ERROR_INVALID_HANDLE indicates we are disconnected
                 if (errno == ERROR_INVALID_HANDLE)
                     usb_kick(handle);
diff --git a/fastboot/usbtest.c b/fastboot/usbtest.c
index b8fb9e2..e6e2b37 100644
--- a/fastboot/usbtest.c
+++ b/fastboot/usbtest.c
@@ -88,14 +88,14 @@
 
 int test_null(usb_handle *usb)
 {
-    int i;
+    unsigned i;
     unsigned char buf[4096];
     memset(buf, 0xee, 4096);
     long long t0, t1;
 
     t0 = NOW();
     for(i = 0; i < arg_count; i++) {
-        if(usb_write(usb, buf, arg_size) != arg_size) {
+        if(usb_write(usb, buf, arg_size) != (int)arg_size) {
             fprintf(stderr,"write failed (%s)\n", strerror(errno));
             return -1;
         }
@@ -107,13 +107,13 @@
 
 int test_zero(usb_handle *usb)
 {
-    int i;
+    unsigned i;
     unsigned char buf[4096];
     long long t0, t1;
 
     t0 = NOW();
     for(i = 0; i < arg_count; i++) {
-        if(usb_read(usb, buf, arg_size) != arg_size) {
+        if(usb_read(usb, buf, arg_size) != (int)arg_size) {
             fprintf(stderr,"read failed (%s)\n", strerror(errno));
             return -1;
         }
@@ -130,11 +130,11 @@
     int (*test)(usb_handle *usb);
     const char *help;
 } tests[] = {
-    { "list", printifc,   0,         "list interfaces" },
+    { "list", printifc,   NULL,      "list interfaces" },
     { "send", match_null, test_null, "send to null interface" },
     { "recv", match_zero, test_zero, "recv from zero interface" },
-    { "loop", match_loop, 0,         "exercise loopback interface" },
-    {},
+    { "loop", match_loop, NULL,      "exercise loopback interface" },
+    { NULL, NULL, NULL, NULL },
 };
 
 int usage(void)
diff --git a/fastbootd/Android.mk b/fastbootd/Android.mk
index 0f32dbf..6aa7400 100644
--- a/fastbootd/Android.mk
+++ b/fastbootd/Android.mk
@@ -45,19 +45,17 @@
 LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter -DFLASH_CERT
 LOCAL_LDFLAGS := -ldl
 
-LOCAL_SHARED_LIBRARIES := \
-    libhardware \
-    libcrypto \
-    libhardware_legacy \
-    libmdnssd
-
 LOCAL_STATIC_LIBRARIES := \
-    libsparse_static \
     libc \
+    libcrypto_static \
     libcutils \
+    libmdnssd \
+    libsparse_static \
     libz
 
-#LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_HAL_STATIC_LIBRARIES := libvendortrigger
+
+LOCAL_FORCE_STATIC_EXECUTABLE := true
 
 include $(BUILD_EXECUTABLE)
 
@@ -84,21 +82,11 @@
 
 include $(BUILD_EXECUTABLE)
 
+# vendor trigger HAL
 include $(CLEAR_VARS)
-
-LOCAL_C_INCLUDES := \
-    $(LOCAL_PATH)/include \
-
-LOCAL_STATIC_LIBRARIES := \
-    $(EXTRA_STATIC_LIBS) \
-    libcutils
-
-LOCAL_SRC_FILES := \
-    other/vendor_trigger.c
-
+LOCAL_CFLAGS := -Wall -Werror
 LOCAL_MODULE := libvendortrigger.default
 LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter
-
-
-include $(BUILD_SHARED_LIBRARY)
+LOCAL_SRC_FILES := vendor_trigger_default.c
+LOCAL_STATIC_LIBRARIES := libcutils
+include $(BUILD_STATIC_LIBRARY)
diff --git a/fastbootd/commands.c b/fastbootd/commands.c
index 063e1a6..98b7866 100644
--- a/fastbootd/commands.c
+++ b/fastbootd/commands.c
@@ -124,9 +124,9 @@
         goto error;
     }
 
-    kernel_ptr = (void *)((unsigned) ptr + hdr->page_size);
-    ramdisk_ptr = (void *)((unsigned) kernel_ptr + kernel_actual);
-    second_ptr = (void *)((unsigned) ramdisk_ptr + ramdisk_actual);
+    kernel_ptr = (void *)((uintptr_t) ptr + hdr->page_size);
+    ramdisk_ptr = (void *)((uintptr_t) kernel_ptr + kernel_actual);
+    second_ptr = (void *)((uintptr_t) ramdisk_ptr + ramdisk_actual);
 
     D(INFO, "preparing to boot");
     // Prepares boot physical address. Addresses from header are ignored
diff --git a/fastbootd/commands/boot.c b/fastbootd/commands/boot.c
index 8da9a28..922914b 100644
--- a/fastbootd/commands/boot.c
+++ b/fastbootd/commands/boot.c
@@ -89,10 +89,10 @@
  * Kernel address is not set into kernel_phys
  * Ramdisk is set to position relative to kernel
  */
-int prepare_boot_linux(unsigned kernel_phys, void *kernel_addr, int kernel_size,
-                       unsigned ramdisk_phys, void *ramdisk_addr, int ramdisk_size,
-                       unsigned second_phys, void *second_addr, int second_size,
-                       unsigned atags_phys, void *atags_addr, int atags_size) {
+int prepare_boot_linux(uintptr_t kernel_phys, void *kernel_addr, int kernel_size,
+                       uintptr_t ramdisk_phys, void *ramdisk_addr, int ramdisk_size,
+                       uintptr_t second_phys, void *second_addr, int second_size,
+                       uintptr_t atags_phys, void *atags_addr, int atags_size) {
     struct kexec_segment segment[4];
     int segment_count = 2;
     unsigned entry = START_ADDRESS + KEXEC_ARM_ZIMAGE_OFFSET;
diff --git a/fastbootd/commands/boot.h b/fastbootd/commands/boot.h
index 901c38a..a5efd01 100644
--- a/fastbootd/commands/boot.h
+++ b/fastbootd/commands/boot.h
@@ -40,8 +40,8 @@
 #define KEXEC_TYPE_DEFAULT 0
 #define KEXEC_TYPE_CRASH   1
 
-int prepare_boot_linux(unsigned, void *, int, unsigned, void *, int,
-                       unsigned, void *, int, unsigned, void *, int);
+int prepare_boot_linux(uintptr_t, void *, int, uintptr_t, void *, int,
+                       uintptr_t, void *, int, uintptr_t, void *, int);
 unsigned *create_atags(unsigned *, int, const struct boot_img_hdr *, int *);
 long kexec_load(unsigned int, unsigned long, struct kexec_segment *, unsigned long);
 char *read_atags(const char *, int *);
diff --git a/fastbootd/other/vendor_trigger.c b/fastbootd/other/vendor_trigger.c
deleted file mode 100644
index 101959b..0000000
--- a/fastbootd/other/vendor_trigger.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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 <stdlib.h>
-
-#include "vendor_trigger.h"
-#include "debug.h"
-
-unsigned int debug_level = DEBUG;
-
-static const int version = 1;
-
-int check_version(const int fastboot_version, int *libversion) {
-    *libversion = version;
-    return !(fastboot_version == version);
-}
-
-int gpt_layout(struct GPT_content *table) {
-    D(DEBUG, "message from libvendor");
-    return 0;
-}
-
-int oem_cmd(const char *arg, const char **response) {
-    D(DEBUG, "message from libvendor, oem catched request %s", arg);
-    return 0;
-}
-
-static int close_triggers(struct vendor_trigger_t *dev)
-{
-    if (dev)
-        free(dev);
-
-    return 0;
-}
-
-static int open_triggers(const struct hw_module_t *module, char const *name,
-                         struct hw_device_t **device) {
-    struct vendor_trigger_t *dev = malloc(sizeof(struct vendor_trigger_t));
-    klog_init();
-    klog_set_level(6);
-
-    memset(dev, 0, sizeof(*dev));
-    dev->common.module = (struct hw_module_t *) module;
-    dev->common.close  = (int (*)(struct hw_device_t *)) close_triggers;
-
-    dev->gpt_layout = gpt_layout;
-    dev->oem_cmd = oem_cmd;
-
-    *device = (struct hw_device_t *) dev;
-
-    return 0;
-}
-
-
-static struct hw_module_methods_t trigger_module_methods = {
-    .open = open_triggers,
-};
-
-struct hw_module_t HAL_MODULE_INFO_SYM = {
-    .tag = HARDWARE_MODULE_TAG,
-    .version_major = 1,
-    .version_minor = 0,
-    .id = TRIGGER_MODULE_ID,
-    .name = "vendor trigger library for fastbootd",
-    .author = "Google, Inc.",
-    .methods = &trigger_module_methods,
-};
-
diff --git a/fastbootd/protocol.c b/fastbootd/protocol.c
index 0086b4a..3908020 100644
--- a/fastbootd/protocol.c
+++ b/fastbootd/protocol.c
@@ -142,7 +142,7 @@
     char response[64];
     ssize_t ret;
 
-    snprintf(response, 64, "DATA%08x", len);
+    snprintf(response, 64, "DATA%08zx", len);
     ret = protocol_handle_write(phandle, response, strlen(response));
     if (ret < 0)
         return;
diff --git a/fastbootd/transport.c b/fastbootd/transport.c
index ce8f9d0..9a16fd7 100644
--- a/fastbootd/transport.c
+++ b/fastbootd/transport.c
@@ -55,7 +55,7 @@
     ftruncate(fd, len);
 
     buffer = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-    if (buffer == NULL) {
+    if (buffer == MAP_FAILED) {
         D(ERR, "mmap(%zu) failed: %d %s", len, errno, strerror(errno));
         goto err;
     }
diff --git a/fastbootd/trigger.c b/fastbootd/trigger.c
index e63e64d..df0f895 100644
--- a/fastbootd/trigger.c
+++ b/fastbootd/trigger.c
@@ -39,52 +39,19 @@
 
 static const int version = 1;
 
-static struct vendor_trigger_t *triggers = NULL;
-
 int load_trigger() {
-    int err;
-    hw_module_t* module;
-    hw_device_t* device;
     int libversion;
 
-    err = hw_get_module(TRIGGER_MODULE_ID, (hw_module_t const**)&module);
-
-    if (err == 0) {
-        err = module->methods->open(module, NULL, &device);
-
-        if (err == 0) {
-            triggers = (struct vendor_trigger_t *) device;
-        } else {
-            D(WARN, "Libvendor load error");
-            return 1;
-        }
-    }
-    else {
-        D(WARN, "Libvendor not load: %s", strerror(-err));
-        return 0;
+    if (trigger_init() != 0) {
+        D(ERR, "libvendortrigger failed to initialize");
+        return 1;
     }
 
-    if (triggers->check_version != NULL &&
-        triggers->check_version(version, &libversion)) {
-
-        triggers = NULL;
+    if (trigger_check_version(version, &libversion)) {
         D(ERR, "Library report incompability");
         return 1;
     }
+
     D(INFO, "libvendortrigger loaded");
-
     return 0;
 }
-
-int trigger_oem_cmd(const char *arg, const char **response) {
-    if (triggers != NULL && triggers->oem_cmd != NULL)
-        return triggers->oem_cmd(arg, response);
-    return 0;
-}
-
-int trigger_gpt_layout(struct GPT_content *table) {
-    if (triggers != NULL && triggers->gpt_layout != NULL)
-        return triggers->gpt_layout(table);
-    return 0;
-}
-
diff --git a/fastbootd/trigger.h b/fastbootd/trigger.h
index 404acb4..d2d9573 100644
--- a/fastbootd/trigger.h
+++ b/fastbootd/trigger.h
@@ -37,9 +37,4 @@
 
 int load_trigger();
 
-/* same as in struct triggers */
-
-int trigger_gpt_layout(struct GPT_content *table);
-int trigger_oem_cmd(const char *arg, const char **response);
-
 #endif
diff --git a/fastbootd/include/vendor_trigger.h b/fastbootd/vendor_trigger.h
similarity index 68%
rename from fastbootd/include/vendor_trigger.h
rename to fastbootd/vendor_trigger.h
index 51204fa..0c83be6 100644
--- a/fastbootd/include/vendor_trigger.h
+++ b/fastbootd/vendor_trigger.h
@@ -32,38 +32,37 @@
 #ifndef __VENDOR_TRIGGER_H_
 #define __VENDOR_TRIGGER_H_
 
-#define TRIGGER_MODULE_ID "fastbootd"
-#include <hardware/hardware.h>
-
 __BEGIN_DECLS
 
 struct GPT_entry_raw;
 struct GPT_content;
 
 /*
- * Structer with function pointers may become longer in the future
+ * Implemented in libvendortrigger to handle platform-specific behavior.
  */
 
-struct vendor_trigger_t {
-    struct hw_device_t common;
+/*
+ * trigger_init() is called once at startup time before calling any other method
+ *
+ * returns 0 on success and nonzero on error
+ */
+int trigger_init(void);
 
-    /*
-     * This function runs at the beggining and shoud never be changed
-     *
-     * version is number parameter indicating version on the fastbootd side
-     * libversion is version indicateing version of the library version
-     *
-     * returns 0 if it can cooperate with the current version and 1 in opposite
-     */
-    int (*check_version)(const int version, int *libversion);
+/*
+ * This function runs once after trigger_init completes.
+ *
+ * version is number parameter indicating version on the fastbootd side
+ * libversion is version indicateing version of the library version
+ *
+ * returns 0 if it can cooperate with the current version and 1 in opposite
+ */
+int trigger_check_version(const int version, int *libversion);
 
-
-    /*
-     * Return value -1 forbid the action from the vendor site and sets errno
-     */
-    int (* gpt_layout)(struct GPT_content *);
-    int (* oem_cmd)(const char *arg, const char **response);
-};
+/*
+ * Return value -1 forbid the action from the vendor site and sets errno
+ */
+int trigger_gpt_layout(struct GPT_content *);
+int trigger_oem_cmd(const char *arg, const char **response);
 
 __END_DECLS
 
diff --git a/fastbootd/include/vendor_trigger.h b/fastbootd/vendor_trigger_default.c
similarity index 62%
copy from fastbootd/include/vendor_trigger.h
copy to fastbootd/vendor_trigger_default.c
index 51204fa..3627024 100644
--- a/fastbootd/include/vendor_trigger.h
+++ b/fastbootd/vendor_trigger_default.c
@@ -29,42 +29,30 @@
  * SUCH DAMAGE.
  */
 
-#ifndef __VENDOR_TRIGGER_H_
-#define __VENDOR_TRIGGER_H_
+#include <stdlib.h>
+#include <cutils/klog.h>
+#include <vendor_trigger.h>
 
-#define TRIGGER_MODULE_ID "fastbootd"
-#include <hardware/hardware.h>
+static const int version = 1;
 
-__BEGIN_DECLS
+int trigger_init(void) {
+    klog_init();
+    klog_set_level(7);
+    return 0;
+}
 
-struct GPT_entry_raw;
-struct GPT_content;
+int trigger_check_version(const int fastboot_version, int *libversion) {
+    KLOG_DEBUG("fastbootd", "%s: %d (%d)", __func__, fastboot_version, version);
+    *libversion = version;
+    return !(fastboot_version == version);
+}
 
-/*
- * Structer with function pointers may become longer in the future
- */
+int trigger_gpt_layout(struct GPT_content *table) {
+    KLOG_DEBUG("fastbootd", "%s: %p", __func__, table);
+    return 0;
+}
 
-struct vendor_trigger_t {
-    struct hw_device_t common;
-
-    /*
-     * This function runs at the beggining and shoud never be changed
-     *
-     * version is number parameter indicating version on the fastbootd side
-     * libversion is version indicateing version of the library version
-     *
-     * returns 0 if it can cooperate with the current version and 1 in opposite
-     */
-    int (*check_version)(const int version, int *libversion);
-
-
-    /*
-     * Return value -1 forbid the action from the vendor site and sets errno
-     */
-    int (* gpt_layout)(struct GPT_content *);
-    int (* oem_cmd)(const char *arg, const char **response);
-};
-
-__END_DECLS
-
-#endif
+int trigger_oem_cmd(const char *arg, const char **response) {
+    KLOG_DEBUG("fastbootd", "%s: %s", __func__, arg);
+    return 0;
+}
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 790598a..7cffc37 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -3,7 +3,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:= fs_mgr.c fs_mgr_verity.c
+LOCAL_SRC_FILES:= fs_mgr.c fs_mgr_verity.c fs_mgr_fstab.c
 
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 
@@ -11,6 +11,7 @@
 LOCAL_STATIC_LIBRARIES := liblogwrap libmincrypt libext4_utils_static
 LOCAL_C_INCLUDES += system/extras/ext4_utils
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Werror
 
 include $(BUILD_STATIC_LIBRARY)
 
@@ -31,5 +32,7 @@
 
 LOCAL_STATIC_LIBRARIES := libfs_mgr liblogwrap libcutils liblog libc libmincrypt libext4_utils_static
 
+LOCAL_CFLAGS := -Werror
+
 include $(BUILD_EXECUTABLE)
 
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 24ce806..dcda005 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -54,55 +54,6 @@
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 
-struct flag_list {
-    const char *name;
-    unsigned flag;
-};
-
-static struct flag_list mount_flags[] = {
-    { "noatime",    MS_NOATIME },
-    { "noexec",     MS_NOEXEC },
-    { "nosuid",     MS_NOSUID },
-    { "nodev",      MS_NODEV },
-    { "nodiratime", MS_NODIRATIME },
-    { "ro",         MS_RDONLY },
-    { "rw",         0 },
-    { "remount",    MS_REMOUNT },
-    { "bind",       MS_BIND },
-    { "rec",        MS_REC },
-    { "unbindable", MS_UNBINDABLE },
-    { "private",    MS_PRIVATE },
-    { "slave",      MS_SLAVE },
-    { "shared",     MS_SHARED },
-    { "defaults",   0 },
-    { 0,            0 },
-};
-
-static struct flag_list fs_mgr_flags[] = {
-    { "wait",        MF_WAIT },
-    { "check",       MF_CHECK },
-    { "encryptable=",MF_CRYPT },
-    { "nonremovable",MF_NONREMOVABLE },
-    { "voldmanaged=",MF_VOLDMANAGED},
-    { "length=",     MF_LENGTH },
-    { "recoveryonly",MF_RECOVERYONLY },
-    { "swapprio=",   MF_SWAPPRIO },
-    { "zramsize=",   MF_ZRAMSIZE },
-    { "verify",      MF_VERIFY },
-    { "noemulatedsd", MF_NOEMULATEDSD },
-    { "defaults",    0 },
-    { 0,             0 },
-};
-
-struct fs_mgr_flag_values {
-    char *key_loc;
-    long long part_length;
-    char *label;
-    int partnum;
-    int swap_prio;
-    unsigned int zram_size;
-};
-
 /*
  * gettime() - returns the time in seconds of the system's monotonic clock or
  * zero on error.
@@ -133,269 +84,6 @@
     return ret;
 }
 
-static int parse_flags(char *flags, struct flag_list *fl,
-                       struct fs_mgr_flag_values *flag_vals,
-                       char *fs_options, int fs_options_len)
-{
-    int f = 0;
-    int i;
-    char *p;
-    char *savep;
-
-    /* initialize flag values.  If we find a relevant flag, we'll
-     * update the value */
-    if (flag_vals) {
-        memset(flag_vals, 0, sizeof(*flag_vals));
-        flag_vals->partnum = -1;
-        flag_vals->swap_prio = -1; /* negative means it wasn't specified. */
-    }
-
-    /* initialize fs_options to the null string */
-    if (fs_options && (fs_options_len > 0)) {
-        fs_options[0] = '\0';
-    }
-
-    p = strtok_r(flags, ",", &savep);
-    while (p) {
-        /* Look for the flag "p" in the flag list "fl"
-         * If not found, the loop exits with fl[i].name being null.
-         */
-        for (i = 0; fl[i].name; i++) {
-            if (!strncmp(p, fl[i].name, strlen(fl[i].name))) {
-                f |= fl[i].flag;
-                if ((fl[i].flag == MF_CRYPT) && flag_vals) {
-                    /* The encryptable flag is followed by an = and the
-                     * location of the keys.  Get it and return it.
-                     */
-                    flag_vals->key_loc = strdup(strchr(p, '=') + 1);
-                } else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
-                    /* The length flag is followed by an = and the
-                     * size of the partition.  Get it and return it.
-                     */
-                    flag_vals->part_length = strtoll(strchr(p, '=') + 1, NULL, 0);
-                } else if ((fl[i].flag == MF_VOLDMANAGED) && flag_vals) {
-                    /* 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) {
-                        flag_vals->label = strndup(label_start,
-                                                   (int) (label_end - label_start));
-                        part_start = strchr(p, ':') + 1;
-                        if (!strcmp(part_start, "auto")) {
-                            flag_vals->partnum = -1;
-                        } else {
-                            flag_vals->partnum = strtol(part_start, NULL, 0);
-                        }
-                    } else {
-                        ERROR("Warning: voldmanaged= flag malformed\n");
-                    }
-                } else if ((fl[i].flag == MF_SWAPPRIO) && flag_vals) {
-                    flag_vals->swap_prio = strtoll(strchr(p, '=') + 1, NULL, 0);
-                } else if ((fl[i].flag == MF_ZRAMSIZE) && flag_vals) {
-                    flag_vals->zram_size = strtoll(strchr(p, '=') + 1, NULL, 0);
-                }
-                break;
-            }
-        }
-
-        if (!fl[i].name) {
-            if (fs_options) {
-                /* It's not a known flag, so it must be a filesystem specific
-                 * option.  Add it to fs_options if it was passed in.
-                 */
-                strlcat(fs_options, p, fs_options_len);
-                strlcat(fs_options, ",", fs_options_len);
-            } else {
-                /* fs_options was not passed in, so if the flag is unknown
-                 * it's an error.
-                 */
-                ERROR("Warning: unknown flag %s\n", p);
-            }
-        }
-        p = strtok_r(NULL, ",", &savep);
-    }
-
-out:
-    if (fs_options && fs_options[0]) {
-        /* remove the last trailing comma from the list of options */
-        fs_options[strlen(fs_options) - 1] = '\0';
-    }
-
-    return f;
-}
-
-struct fstab *fs_mgr_read_fstab(const char *fstab_path)
-{
-    FILE *fstab_file;
-    int cnt, entries;
-    ssize_t len;
-    size_t alloc_len = 0;
-    char *line = NULL;
-    const char *delim = " \t";
-    char *save_ptr, *p;
-    struct fstab *fstab = NULL;
-    struct fstab_rec *recs;
-    struct fs_mgr_flag_values flag_vals;
-#define FS_OPTIONS_LEN 1024
-    char tmp_fs_options[FS_OPTIONS_LEN];
-
-    fstab_file = fopen(fstab_path, "r");
-    if (!fstab_file) {
-        ERROR("Cannot open file %s\n", fstab_path);
-        return 0;
-    }
-
-    entries = 0;
-    while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
-        /* if the last character is a newline, shorten the string by 1 byte */
-        if (line[len - 1] == '\n') {
-            line[len - 1] = '\0';
-        }
-        /* Skip any leading whitespace */
-        p = line;
-        while (isspace(*p)) {
-            p++;
-        }
-        /* ignore comments or empty lines */
-        if (*p == '#' || *p == '\0')
-            continue;
-        entries++;
-    }
-
-    if (!entries) {
-        ERROR("No entries found in fstab\n");
-        goto err;
-    }
-
-    /* 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);
-
-    cnt = 0;
-    while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
-        /* if the last character is a newline, shorten the string by 1 byte */
-        if (line[len - 1] == '\n') {
-            line[len - 1] = '\0';
-        }
-
-        /* Skip any leading whitespace */
-        p = line;
-        while (isspace(*p)) {
-            p++;
-        }
-        /* ignore comments or empty lines */
-        if (*p == '#' || *p == '\0')
-            continue;
-
-        /* If a non-comment entry is greater than the size we allocated, give an
-         * error and quit.  This can happen in the unlikely case the file changes
-         * between the two reads.
-         */
-        if (cnt >= entries) {
-            ERROR("Tried to process more entries than counted\n");
-            break;
-        }
-
-        if (!(p = strtok_r(line, delim, &save_ptr))) {
-            ERROR("Error parsing mount source\n");
-            goto err;
-        }
-        fstab->recs[cnt].blk_device = strdup(p);
-
-        if (!(p = strtok_r(NULL, delim, &save_ptr))) {
-            ERROR("Error parsing mount_point\n");
-            goto err;
-        }
-        fstab->recs[cnt].mount_point = strdup(p);
-
-        if (!(p = strtok_r(NULL, delim, &save_ptr))) {
-            ERROR("Error parsing fs_type\n");
-            goto err;
-        }
-        fstab->recs[cnt].fs_type = strdup(p);
-
-        if (!(p = strtok_r(NULL, delim, &save_ptr))) {
-            ERROR("Error parsing mount_flags\n");
-            goto err;
-        }
-        tmp_fs_options[0] = '\0';
-        fstab->recs[cnt].flags = parse_flags(p, mount_flags, NULL,
-                                       tmp_fs_options, FS_OPTIONS_LEN);
-
-        /* fs_options are optional */
-        if (tmp_fs_options[0]) {
-            fstab->recs[cnt].fs_options = strdup(tmp_fs_options);
-        } else {
-            fstab->recs[cnt].fs_options = NULL;
-        }
-
-        if (!(p = strtok_r(NULL, delim, &save_ptr))) {
-            ERROR("Error parsing fs_mgr_options\n");
-            goto err;
-        }
-        fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
-                                                    &flag_vals, NULL, 0);
-        fstab->recs[cnt].key_loc = flag_vals.key_loc;
-        fstab->recs[cnt].length = flag_vals.part_length;
-        fstab->recs[cnt].label = flag_vals.label;
-        fstab->recs[cnt].partnum = flag_vals.partnum;
-        fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
-        fstab->recs[cnt].zram_size = flag_vals.zram_size;
-        cnt++;
-    }
-    fclose(fstab_file);
-    free(line);
-    return fstab;
-
-err:
-    fclose(fstab_file);
-    free(line);
-    if (fstab)
-        fs_mgr_free_fstab(fstab);
-    return NULL;
-}
-
-void fs_mgr_free_fstab(struct fstab *fstab)
-{
-    int i;
-
-    if (!fstab) {
-        return;
-    }
-
-    for (i = 0; i < fstab->num_entries; i++) {
-        /* Free the pointers return by strdup(3) */
-        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);
-    }
-
-    /* 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_device, char *fs_type, char *target)
 {
     int status;
@@ -428,15 +116,24 @@
             umount(target);
         }
 
-        INFO("Running %s on %s\n", E2FSCK_BIN, blk_device);
+        /*
+         * Some system images do not have e2fsck for licensing reasons
+         * (e.g. recent SDK system images). Detect these and skip the check.
+         */
+        if (access(E2FSCK_BIN, X_OK)) {
+            INFO("Not running %s on %s (executable not in system image)\n",
+                 E2FSCK_BIN, blk_device);
+        } else {
+            INFO("Running %s on %s\n", E2FSCK_BIN, blk_device);
 
-        ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv), e2fsck_argv,
-                                      &status, true, LOG_KLOG | LOG_FILE,
-                                      true, FSCK_LOG_FILE);
+            ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv), e2fsck_argv,
+                                        &status, true, LOG_KLOG | LOG_FILE,
+                                        true, FSCK_LOG_FILE);
 
-        if (ret < 0) {
-            /* No need to check for error in fork, we can't really handle it now */
-            ERROR("Failed trying to run %s\n", E2FSCK_BIN);
+            if (ret < 0) {
+                /* No need to check for error in fork, we can't really handle it now */
+                ERROR("Failed trying to run %s\n", E2FSCK_BIN);
+            }
         }
     }
 
@@ -823,71 +520,3 @@
 
     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;
-}
-
-int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab)
-{
-    return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
-}
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
new file mode 100644
index 0000000..f86fc6a
--- /dev/null
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2014 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 <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+
+#include "fs_mgr_priv.h"
+
+struct fs_mgr_flag_values {
+    char *key_loc;
+    long long part_length;
+    char *label;
+    int partnum;
+    int swap_prio;
+    unsigned int zram_size;
+};
+
+struct flag_list {
+    const char *name;
+    unsigned flag;
+};
+
+static struct flag_list mount_flags[] = {
+    { "noatime",    MS_NOATIME },
+    { "noexec",     MS_NOEXEC },
+    { "nosuid",     MS_NOSUID },
+    { "nodev",      MS_NODEV },
+    { "nodiratime", MS_NODIRATIME },
+    { "ro",         MS_RDONLY },
+    { "rw",         0 },
+    { "remount",    MS_REMOUNT },
+    { "bind",       MS_BIND },
+    { "rec",        MS_REC },
+    { "unbindable", MS_UNBINDABLE },
+    { "private",    MS_PRIVATE },
+    { "slave",      MS_SLAVE },
+    { "shared",     MS_SHARED },
+    { "defaults",   0 },
+    { 0,            0 },
+};
+
+static struct flag_list fs_mgr_flags[] = {
+    { "wait",        MF_WAIT },
+    { "check",       MF_CHECK },
+    { "encryptable=",MF_CRYPT },
+    { "nonremovable",MF_NONREMOVABLE },
+    { "voldmanaged=",MF_VOLDMANAGED},
+    { "length=",     MF_LENGTH },
+    { "recoveryonly",MF_RECOVERYONLY },
+    { "swapprio=",   MF_SWAPPRIO },
+    { "zramsize=",   MF_ZRAMSIZE },
+    { "verify",      MF_VERIFY },
+    { "noemulatedsd", MF_NOEMULATEDSD },
+    { "defaults",    0 },
+    { 0,             0 },
+};
+
+static int parse_flags(char *flags, struct flag_list *fl,
+                       struct fs_mgr_flag_values *flag_vals,
+                       char *fs_options, int fs_options_len)
+{
+    int f = 0;
+    int i;
+    char *p;
+    char *savep;
+
+    /* initialize flag values.  If we find a relevant flag, we'll
+     * update the value */
+    if (flag_vals) {
+        memset(flag_vals, 0, sizeof(*flag_vals));
+        flag_vals->partnum = -1;
+        flag_vals->swap_prio = -1; /* negative means it wasn't specified. */
+    }
+
+    /* initialize fs_options to the null string */
+    if (fs_options && (fs_options_len > 0)) {
+        fs_options[0] = '\0';
+    }
+
+    p = strtok_r(flags, ",", &savep);
+    while (p) {
+        /* Look for the flag "p" in the flag list "fl"
+         * If not found, the loop exits with fl[i].name being null.
+         */
+        for (i = 0; fl[i].name; i++) {
+            if (!strncmp(p, fl[i].name, strlen(fl[i].name))) {
+                f |= fl[i].flag;
+                if ((fl[i].flag == MF_CRYPT) && flag_vals) {
+                    /* The encryptable flag is followed by an = and the
+                     * location of the keys.  Get it and return it.
+                     */
+                    flag_vals->key_loc = strdup(strchr(p, '=') + 1);
+                } else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
+                    /* The length flag is followed by an = and the
+                     * size of the partition.  Get it and return it.
+                     */
+                    flag_vals->part_length = strtoll(strchr(p, '=') + 1, NULL, 0);
+                } else if ((fl[i].flag == MF_VOLDMANAGED) && flag_vals) {
+                    /* 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) {
+                        flag_vals->label = strndup(label_start,
+                                                   (int) (label_end - label_start));
+                        part_start = strchr(p, ':') + 1;
+                        if (!strcmp(part_start, "auto")) {
+                            flag_vals->partnum = -1;
+                        } else {
+                            flag_vals->partnum = strtol(part_start, NULL, 0);
+                        }
+                    } else {
+                        ERROR("Warning: voldmanaged= flag malformed\n");
+                    }
+                } else if ((fl[i].flag == MF_SWAPPRIO) && flag_vals) {
+                    flag_vals->swap_prio = strtoll(strchr(p, '=') + 1, NULL, 0);
+                } else if ((fl[i].flag == MF_ZRAMSIZE) && flag_vals) {
+                    flag_vals->zram_size = strtoll(strchr(p, '=') + 1, NULL, 0);
+                }
+                break;
+            }
+        }
+
+        if (!fl[i].name) {
+            if (fs_options) {
+                /* It's not a known flag, so it must be a filesystem specific
+                 * option.  Add it to fs_options if it was passed in.
+                 */
+                strlcat(fs_options, p, fs_options_len);
+                strlcat(fs_options, ",", fs_options_len);
+            } else {
+                /* fs_options was not passed in, so if the flag is unknown
+                 * it's an error.
+                 */
+                ERROR("Warning: unknown flag %s\n", p);
+            }
+        }
+        p = strtok_r(NULL, ",", &savep);
+    }
+
+    if (fs_options && fs_options[0]) {
+        /* remove the last trailing comma from the list of options */
+        fs_options[strlen(fs_options) - 1] = '\0';
+    }
+
+    return f;
+}
+
+struct fstab *fs_mgr_read_fstab(const char *fstab_path)
+{
+    FILE *fstab_file;
+    int cnt, entries;
+    ssize_t len;
+    size_t alloc_len = 0;
+    char *line = NULL;
+    const char *delim = " \t";
+    char *save_ptr, *p;
+    struct fstab *fstab = NULL;
+    struct fs_mgr_flag_values flag_vals;
+#define FS_OPTIONS_LEN 1024
+    char tmp_fs_options[FS_OPTIONS_LEN];
+
+    fstab_file = fopen(fstab_path, "r");
+    if (!fstab_file) {
+        ERROR("Cannot open file %s\n", fstab_path);
+        return 0;
+    }
+
+    entries = 0;
+    while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
+        /* if the last character is a newline, shorten the string by 1 byte */
+        if (line[len - 1] == '\n') {
+            line[len - 1] = '\0';
+        }
+        /* Skip any leading whitespace */
+        p = line;
+        while (isspace(*p)) {
+            p++;
+        }
+        /* ignore comments or empty lines */
+        if (*p == '#' || *p == '\0')
+            continue;
+        entries++;
+    }
+
+    if (!entries) {
+        ERROR("No entries found in fstab\n");
+        goto err;
+    }
+
+    /* 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);
+
+    cnt = 0;
+    while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
+        /* if the last character is a newline, shorten the string by 1 byte */
+        if (line[len - 1] == '\n') {
+            line[len - 1] = '\0';
+        }
+
+        /* Skip any leading whitespace */
+        p = line;
+        while (isspace(*p)) {
+            p++;
+        }
+        /* ignore comments or empty lines */
+        if (*p == '#' || *p == '\0')
+            continue;
+
+        /* If a non-comment entry is greater than the size we allocated, give an
+         * error and quit.  This can happen in the unlikely case the file changes
+         * between the two reads.
+         */
+        if (cnt >= entries) {
+            ERROR("Tried to process more entries than counted\n");
+            break;
+        }
+
+        if (!(p = strtok_r(line, delim, &save_ptr))) {
+            ERROR("Error parsing mount source\n");
+            goto err;
+        }
+        fstab->recs[cnt].blk_device = strdup(p);
+
+        if (!(p = strtok_r(NULL, delim, &save_ptr))) {
+            ERROR("Error parsing mount_point\n");
+            goto err;
+        }
+        fstab->recs[cnt].mount_point = strdup(p);
+
+        if (!(p = strtok_r(NULL, delim, &save_ptr))) {
+            ERROR("Error parsing fs_type\n");
+            goto err;
+        }
+        fstab->recs[cnt].fs_type = strdup(p);
+
+        if (!(p = strtok_r(NULL, delim, &save_ptr))) {
+            ERROR("Error parsing mount_flags\n");
+            goto err;
+        }
+        tmp_fs_options[0] = '\0';
+        fstab->recs[cnt].flags = parse_flags(p, mount_flags, NULL,
+                                       tmp_fs_options, FS_OPTIONS_LEN);
+
+        /* fs_options are optional */
+        if (tmp_fs_options[0]) {
+            fstab->recs[cnt].fs_options = strdup(tmp_fs_options);
+        } else {
+            fstab->recs[cnt].fs_options = NULL;
+        }
+
+        if (!(p = strtok_r(NULL, delim, &save_ptr))) {
+            ERROR("Error parsing fs_mgr_options\n");
+            goto err;
+        }
+        fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
+                                                    &flag_vals, NULL, 0);
+        fstab->recs[cnt].key_loc = flag_vals.key_loc;
+        fstab->recs[cnt].length = flag_vals.part_length;
+        fstab->recs[cnt].label = flag_vals.label;
+        fstab->recs[cnt].partnum = flag_vals.partnum;
+        fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
+        fstab->recs[cnt].zram_size = flag_vals.zram_size;
+        cnt++;
+    }
+    fclose(fstab_file);
+    free(line);
+    return fstab;
+
+err:
+    fclose(fstab_file);
+    free(line);
+    if (fstab)
+        fs_mgr_free_fstab(fstab);
+    return NULL;
+}
+
+void fs_mgr_free_fstab(struct fstab *fstab)
+{
+    int i;
+
+    if (!fstab) {
+        return;
+    }
+
+    for (i = 0; i < fstab->num_entries; i++) {
+        /* Free the pointers return by strdup(3) */
+        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);
+    }
+
+    /* Free the fstab_recs array created by calloc(3) */
+    free(fstab->recs);
+
+    /* Free the fstab filename */
+    free(fstab->fstab_filename);
+
+    /* Free fstab */
+    free(fstab);
+}
+
+/* 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)
+{
+    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;
+}
+
+int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
+}
diff --git a/fs_mgr/fs_mgr_main.c b/fs_mgr/fs_mgr_main.c
index 4bde4a1..e5a00d5 100644
--- a/fs_mgr/fs_mgr_main.c
+++ b/fs_mgr/fs_mgr_main.c
@@ -80,10 +80,10 @@
     int a_flag=0;
     int u_flag=0;
     int n_flag=0;
-    char *n_name;
-    char *n_blk_dev;
-    char *fstab_file;
-    struct fstab *fstab;
+    char *n_name=NULL;
+    char *n_blk_dev=NULL;
+    char *fstab_file=NULL;
+    struct fstab *fstab=NULL;
 
     klog_init();
     klog_set_level(6);
diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c
index 1549316..c9a2a9b 100644
--- a/fs_mgr/fs_mgr_verity.c
+++ b/fs_mgr/fs_mgr_verity.c
@@ -36,8 +36,7 @@
 #include "mincrypt/sha.h"
 #include "mincrypt/sha256.h"
 
-#include "ext4_utils.h"
-#include "ext4.h"
+#include "ext4_sb.h"
 
 #include "fs_mgr_priv.h"
 #include "fs_mgr_priv_verity.h"
@@ -86,7 +85,6 @@
 
 static int verify_table(char *signature, char *table, int table_length)
 {
-    int fd;
     RSAPublicKey *key;
     uint8_t hash_buf[SHA_DIGEST_SIZE];
     int retval = -1;
@@ -122,6 +120,7 @@
 {
     int data_device;
     struct ext4_super_block sb;
+    struct fs_info info = {0};
 
     data_device = open(blk_device, O_RDONLY);
     if (data_device < 0) {
@@ -141,7 +140,7 @@
         return -1;
     }
 
-    ext4_parse_sb(&sb);
+    ext4_parse_sb(&sb, &info);
     *device_size = info.len;
 
     close(data_device);
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 0f90c32..835cf64 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -57,7 +57,7 @@
                           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);
+                     const char *blk_device);
 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);
diff --git a/gpttool/Android.mk b/gpttool/Android.mk
index b8f9844..64ad945 100644
--- a/gpttool/Android.mk
+++ b/gpttool/Android.mk
@@ -5,6 +5,7 @@
 
 LOCAL_SRC_FILES := gpttool.c
 LOCAL_STATIC_LIBRARIES := libz
+LOCAL_CFLAGS := -Werror
 
 LOCAL_MODULE := gpttool
 
diff --git a/gpttool/gpttool.c b/gpttool/gpttool.c
index d3f08fe..398362f 100644
--- a/gpttool/gpttool.c
+++ b/gpttool/gpttool.c
@@ -1,5 +1,4 @@
-/* system/core/gpttool/gpttool.c
-**
+/*
 ** Copyright 2011, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,18 +14,18 @@
 ** limitations under the License.
 */
 
+#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
 #include <string.h>
-#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
 #include <zlib.h>
 
 #include <linux/fs.h>
 
-#include <sys/stat.h>
-
 typedef unsigned char u8;
 typedef unsigned short u16;
 typedef unsigned int u32;
@@ -252,11 +251,9 @@
 int main(int argc, char **argv)
 {
 	struct ptable ptbl;
-	struct efi_entry *entry;
 	struct efi_header *hdr = &ptbl.header;
-	struct stat s;
 	u32 n;
-	u64 sz, blk;
+	u64 sz;
 	int fd;
 	const char *device;
 	int real_disk = 0;
diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
index 9b84c3e..d30e771 100644
--- a/healthd/healthd.cpp
+++ b/healthd/healthd.cpp
@@ -126,7 +126,7 @@
         KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
 }
 
-#define UEVENT_MSG_LEN 1024
+#define UEVENT_MSG_LEN 2048
 static void uevent_event(void) {
     char msg[UEVENT_MSG_LEN+2];
     char *cp;
diff --git a/healthd/healthd_board_default.cpp b/healthd/healthd_board_default.cpp
index b2bb516..ed4ddb4 100644
--- a/healthd/healthd_board_default.cpp
+++ b/healthd/healthd_board_default.cpp
@@ -16,13 +16,13 @@
 
 #include <healthd.h>
 
-void healthd_board_init(struct healthd_config *config)
+void healthd_board_init(struct healthd_config*)
 {
     // use defaults
 }
 
 
-int healthd_board_battery_update(struct android::BatteryProperties *props)
+int healthd_board_battery_update(struct android::BatteryProperties*)
 {
     // return 0 to log periodic polled battery status to kernel log
     return 0;
diff --git a/include/android/log.h b/include/android/log.h
index 0ea4c29..1c171b7 100644
--- a/include/android/log.h
+++ b/include/android/log.h
@@ -98,8 +98,16 @@
  */
 int __android_log_print(int prio, const char *tag,  const char *fmt, ...)
 #if defined(__GNUC__)
+#ifdef __USE_MINGW_ANSI_STDIO
+#if __USE_MINGW_ANSI_STDIO
+    __attribute__ ((format(gnu_printf, 3, 4)))
+#else
     __attribute__ ((format(printf, 3, 4)))
 #endif
+#else
+    __attribute__ ((format(printf, 3, 4)))
+#endif
+#endif
     ;
 
 /*
@@ -110,15 +118,23 @@
                          const char *fmt, va_list ap);
 
 /*
- * Log an assertion failure and SIGTRAP the process to have a chance
- * to inspect it, if a debugger is attached. This uses the FATAL priority.
+ * Log an assertion failure and abort the process to have a chance
+ * to inspect it if a debugger is attached. This uses the FATAL priority.
  */
 void __android_log_assert(const char *cond, const char *tag,
-			  const char *fmt, ...)    
+                          const char *fmt, ...)
 #if defined(__GNUC__)
     __attribute__ ((noreturn))
+#ifdef __USE_MINGW_ANSI_STDIO
+#if __USE_MINGW_ANSI_STDIO
+    __attribute__ ((format(gnu_printf, 3, 4)))
+#else
     __attribute__ ((format(printf, 3, 4)))
 #endif
+#else
+    __attribute__ ((format(printf, 3, 4)))
+#endif
+#endif
     ;
 
 #ifdef __cplusplus
diff --git a/include/backtrace/Backtrace.h b/include/backtrace/Backtrace.h
index bd4134c..e07d322 100644
--- a/include/backtrace/Backtrace.h
+++ b/include/backtrace/Backtrace.h
@@ -17,6 +17,7 @@
 #ifndef _BACKTRACE_BACKTRACE_H
 #define _BACKTRACE_BACKTRACE_H
 
+#include <inttypes.h>
 #include <stdint.h>
 
 #include <string>
@@ -25,6 +26,14 @@
 #include <backtrace/backtrace_constants.h>
 #include <backtrace/BacktraceMap.h>
 
+#if __LP64__
+#define PRIPTR "016" PRIxPTR
+typedef uint64_t word_t;
+#else
+#define PRIPTR "08" PRIxPTR
+typedef uint32_t word_t;
+#endif
+
 struct backtrace_frame_data_t {
   size_t num;             // The current fame number.
   uintptr_t pc;           // The absolute pc.
@@ -38,6 +47,14 @@
 // Forward declarations.
 class BacktraceImpl;
 
+#if defined(__APPLE__)
+struct __darwin_ucontext;
+typedef __darwin_ucontext ucontext_t;
+#else
+struct ucontext;
+typedef ucontext ucontext_t;
+#endif
+
 class Backtrace {
 public:
   // Create the correct Backtrace object based on what is to be unwound.
@@ -55,7 +72,7 @@
   virtual ~Backtrace();
 
   // Get the current stack trace and store in the backtrace_ structure.
-  virtual bool Unwind(size_t num_ignore_frames);
+  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* context = NULL);
 
   // Get the function name and offset into the function given the pc.
   // If the string is empty, then no valid function name was found.
@@ -65,7 +82,7 @@
   virtual const backtrace_map_t* FindMap(uintptr_t pc);
 
   // Read the data at a specific address.
-  virtual bool ReadWord(uintptr_t ptr, uint32_t* out_value) = 0;
+  virtual bool ReadWord(uintptr_t ptr, word_t* out_value) = 0;
 
   // Create a string representing the formatted line of backtrace information
   // for a single frame.
@@ -96,7 +113,7 @@
 protected:
   Backtrace(BacktraceImpl* impl, pid_t pid, BacktraceMap* map);
 
-  virtual bool VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value);
+  virtual bool VerifyReadWordArgs(uintptr_t ptr, word_t* out_value);
 
   bool BuildMap();
 
diff --git a/include/backtrace/BacktraceMap.h b/include/backtrace/BacktraceMap.h
index 06da2f4..c717f09 100644
--- a/include/backtrace/BacktraceMap.h
+++ b/include/backtrace/BacktraceMap.h
@@ -18,6 +18,7 @@
 #define _BACKTRACE_BACKTRACE_MAP_H
 
 #include <stdint.h>
+#include <sys/types.h>
 #ifdef USE_MINGW
 // MINGW does not define these constants.
 #define PROT_NONE 0
@@ -45,7 +46,7 @@
   virtual ~BacktraceMap();
 
   // Get the map data structure for the given address.
-  const backtrace_map_t* Find(uintptr_t addr);
+  virtual const backtrace_map_t* Find(uintptr_t addr);
 
   // The flags returned are the same flags as used by the mmap call.
   // The values are PROT_*.
diff --git a/include/corkscrew/backtrace.h b/include/corkscrew/backtrace.h
deleted file mode 100644
index 556ad04..0000000
--- a/include/corkscrew/backtrace.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* A stack unwinder. */
-
-#ifndef _CORKSCREW_BACKTRACE_H
-#define _CORKSCREW_BACKTRACE_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <sys/types.h>
-#include <corkscrew/ptrace.h>
-#include <corkscrew/map_info.h>
-#include <corkscrew/symbol_table.h>
-
-/*
- * Describes a single frame of a backtrace.
- */
-typedef struct {
-    uintptr_t absolute_pc;     /* absolute PC offset */
-    uintptr_t stack_top;       /* top of stack for this frame */
-    size_t stack_size;         /* size of this stack frame */
-} backtrace_frame_t;
-
-/*
- * Describes the symbols associated with a backtrace frame.
- */
-typedef struct {
-    uintptr_t relative_pc;       /* relative frame PC offset from the start of the library,
-                                    or the absolute PC if the library is unknown */
-    uintptr_t relative_symbol_addr; /* relative offset of the symbol from the start of the
-                                    library or 0 if the library is unknown */
-    char* map_name;              /* executable or library name, or NULL if unknown */
-    char* symbol_name;           /* symbol name, or NULL if unknown */
-    char* demangled_name;        /* demangled symbol name, or NULL if unknown */
-} backtrace_symbol_t;
-
-/*
- * Unwinds the call stack for the current thread of execution.
- * Populates the backtrace array with the program counters from the call stack.
- * Returns the number of frames collected, or -1 if an error occurred.
- */
-ssize_t unwind_backtrace(backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth);
-
-/*
- * Unwinds the call stack for a thread within this process.
- * Populates the backtrace array with the program counters from the call stack.
- * Returns the number of frames collected, or -1 if an error occurred.
- *
- * The task is briefly suspended while the backtrace is being collected.
- */
-ssize_t unwind_backtrace_thread(pid_t tid, backtrace_frame_t* backtrace,
-        size_t ignore_depth, size_t max_depth);
-
-/*
- * Unwinds the call stack of a task within a remote process using ptrace().
- * Populates the backtrace array with the program counters from the call stack.
- * Returns the number of frames collected, or -1 if an error occurred.
- */
-ssize_t unwind_backtrace_ptrace(pid_t tid, const ptrace_context_t* context,
-        backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth);
-
-/*
- * Gets the symbols for each frame of a backtrace.
- * The symbols array must be big enough to hold one symbol record per frame.
- * The symbols must later be freed using free_backtrace_symbols.
- */
-void get_backtrace_symbols(const backtrace_frame_t* backtrace, size_t frames,
-        backtrace_symbol_t* backtrace_symbols);
-
-/*
- * Gets the symbols for each frame of a backtrace from a remote process.
- * The symbols array must be big enough to hold one symbol record per frame.
- * The symbols must later be freed using free_backtrace_symbols.
- */
-void get_backtrace_symbols_ptrace(const ptrace_context_t* context,
-        const backtrace_frame_t* backtrace, size_t frames,
-        backtrace_symbol_t* backtrace_symbols);
-
-/*
- * Frees the storage associated with backtrace symbols.
- */
-void free_backtrace_symbols(backtrace_symbol_t* backtrace_symbols, size_t frames);
-
-enum {
-    // A hint for how big to make the line buffer for format_backtrace_line
-    MAX_BACKTRACE_LINE_LENGTH = 800,
-};
-
-/**
- * Formats a line from a backtrace as a zero-terminated string into the specified buffer.
- */
-void format_backtrace_line(unsigned frameNumber, const backtrace_frame_t* frame,
-        const backtrace_symbol_t* symbol, char* buffer, size_t bufferSize);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _CORKSCREW_BACKTRACE_H
diff --git a/include/corkscrew/demangle.h b/include/corkscrew/demangle.h
deleted file mode 100644
index 04b0225..0000000
--- a/include/corkscrew/demangle.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* C++ symbol name demangling. */
-
-#ifndef _CORKSCREW_DEMANGLE_H
-#define _CORKSCREW_DEMANGLE_H
-
-#include <sys/types.h>
-#include <stdbool.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Demangles a C++ symbol name.
- * If name is NULL or if the name cannot be demangled, returns NULL.
- * Otherwise, returns a newly allocated string that contains the demangled name.
- *
- * The caller must free the returned string using free().
- */
-char* demangle_symbol_name(const char* name);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _CORKSCREW_DEMANGLE_H
diff --git a/include/corkscrew/map_info.h b/include/corkscrew/map_info.h
deleted file mode 100644
index 14bfad6..0000000
--- a/include/corkscrew/map_info.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* Process memory map. */
-
-#ifndef _CORKSCREW_MAP_INFO_H
-#define _CORKSCREW_MAP_INFO_H
-
-#include <sys/types.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct map_info {
-    struct map_info* next;
-    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[];
-} map_info_t;
-
-/* Loads memory map from /proc/<tid>/maps. */
-map_info_t* load_map_info_list(pid_t tid);
-
-/* Frees memory map. */
-void free_map_info_list(map_info_t* milist);
-
-/* 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 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);
-
-/* Acquires a reference to the memory map for this process.
- * The result is cached and refreshed automatically.
- * Make sure to release the map info when done. */
-map_info_t* acquire_my_map_info_list();
-
-/* Releases a reference to the map info for this process that was
- * 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
-
-#endif // _CORKSCREW_MAP_INFO_H
diff --git a/include/corkscrew/ptrace.h b/include/corkscrew/ptrace.h
deleted file mode 100644
index 76276d8..0000000
--- a/include/corkscrew/ptrace.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* Useful ptrace() utility functions. */
-
-#ifndef _CORKSCREW_PTRACE_H
-#define _CORKSCREW_PTRACE_H
-
-#include <corkscrew/map_info.h>
-#include <corkscrew/symbol_table.h>
-
-#include <sys/types.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Stores information about a process that is used for several different
- * ptrace() based operations. */
-typedef struct {
-    map_info_t* map_info_list;
-} ptrace_context_t;
-
-/* Describes how to access memory from a process. */
-typedef struct {
-    pid_t tid;
-    const map_info_t* map_info_list;
-} memory_t;
-
-#if __i386__
-/* ptrace() register context. */
-typedef struct pt_regs_x86 {
-    uint32_t ebx;
-    uint32_t ecx;
-    uint32_t edx;
-    uint32_t esi;
-    uint32_t edi;
-    uint32_t ebp;
-    uint32_t eax;
-    uint32_t xds;
-    uint32_t xes;
-    uint32_t xfs;
-    uint32_t xgs;
-    uint32_t orig_eax;
-    uint32_t eip;
-    uint32_t xcs;
-    uint32_t eflags;
-    uint32_t esp;
-    uint32_t xss;
-} pt_regs_x86_t;
-#endif
-
-#if __mips__
-/* ptrace() GET_REGS context. */
-typedef struct pt_regs_mips {
-    uint64_t regs[32];
-    uint64_t lo;
-    uint64_t hi;
-    uint64_t cp0_epc;
-    uint64_t cp0_badvaddr;
-    uint64_t cp0_status;
-    uint64_t cp0_cause;
-} pt_regs_mips_t;
-#endif
-
-/*
- * Initializes a memory structure for accessing memory from this process.
- */
-void init_memory(memory_t* memory, const map_info_t* map_info_list);
-
-/*
- * Initializes a memory structure for accessing memory from another process
- * using ptrace().
- */
-void init_memory_ptrace(memory_t* memory, pid_t tid);
-
-/*
- * Reads a word of memory safely.
- * If the memory is local, ensures that the address is readable before dereferencing it.
- * Returns false and a value of 0xffffffff if the word could not be read.
- */
-bool try_get_word(const memory_t* memory, uintptr_t ptr, uint32_t* out_value);
-
-/*
- * Reads a word of memory safely using ptrace().
- * Returns false and a value of 0xffffffff if the word could not be read.
- */
-bool try_get_word_ptrace(pid_t tid, uintptr_t ptr, uint32_t* out_value);
-
-/*
- * Loads information needed for examining a remote process using ptrace().
- * The caller must already have successfully attached to the process
- * using ptrace().
- *
- * The context can be used for any threads belonging to that process
- * assuming ptrace() is attached to them before performing the actual
- * unwinding.  The context can continue to be used to decode backtraces
- * even after ptrace() has been detached from the process.
- */
-ptrace_context_t* load_ptrace_context(pid_t pid);
-
-/*
- * Frees a ptrace context.
- */
-void free_ptrace_context(ptrace_context_t* context);
-
-/*
- * Finds a symbol using ptrace.
- * Returns the containing map and information about the symbol, or
- * NULL if one or the other is not available.
- */
-void find_symbol_ptrace(const ptrace_context_t* context,
-        uintptr_t addr, const map_info_t** out_map_info, const symbol_t** out_symbol);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _CORKSCREW_PTRACE_H
diff --git a/include/corkscrew/symbol_table.h b/include/corkscrew/symbol_table.h
deleted file mode 100644
index 4998750..0000000
--- a/include/corkscrew/symbol_table.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _CORKSCREW_SYMBOL_TABLE_H
-#define _CORKSCREW_SYMBOL_TABLE_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct {
-    uintptr_t start;
-    uintptr_t end;
-    char* name;
-} symbol_t;
-
-typedef struct {
-    symbol_t* symbols;
-    size_t num_symbols;
-} symbol_table_t;
-
-/*
- * Loads a symbol table from a given file.
- * Returns NULL on error.
- */
-symbol_table_t* load_symbol_table(const char* filename);
-
-/*
- * Frees a symbol table.
- */
-void free_symbol_table(symbol_table_t* table);
-
-/*
- * Finds a symbol associated with an address in the symbol table.
- * Returns NULL if not found.
- */
-const symbol_t* find_symbol(const symbol_table_t* table, uintptr_t addr);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _CORKSCREW_SYMBOL_TABLE_H
diff --git a/include/cutils/atomic-inline.h b/include/cutils/atomic-inline.h
index ae79e00..007a905 100644
--- a/include/cutils/atomic-inline.h
+++ b/include/cutils/atomic-inline.h
@@ -47,8 +47,12 @@
 #include <cutils/atomic-arm64.h>
 #elif defined(__arm__)
 #include <cutils/atomic-arm.h>
-#elif defined(__i386__) || defined(__x86_64__)
+#elif defined(__i386__)
 #include <cutils/atomic-x86.h>
+#elif defined(__x86_64__)
+#include <cutils/atomic-x86_64.h>
+#elif defined(__mips64)
+#include <cutils/atomic-mips64.h>
 #elif defined(__mips__)
 #include <cutils/atomic-mips.h>
 #else
diff --git a/include/cutils/atomic-mips.h b/include/cutils/atomic-mips.h
index f9d3e25..1ed833d 100644
--- a/include/cutils/atomic-mips.h
+++ b/include/cutils/atomic-mips.h
@@ -117,23 +117,6 @@
 
 
 extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_swap(int32_t new_value, volatile int32_t *ptr)
-{
-    int32_t prev, status;
-    do {
-    __asm__ __volatile__ (
-        "    move %[status], %[new_value]\n"
-        "    ll %[prev], (%[ptr])\n"
-        "    sc %[status], (%[ptr])\n"
-        : [prev] "=&r" (prev), [status] "=&r" (status)
-        : [ptr] "r" (ptr), [new_value] "r" (new_value)
-        );
-    } while (__builtin_expect(status == 0, 0));
-    android_memory_barrier();
-    return prev;
-}
-
-extern ANDROID_ATOMIC_INLINE int32_t
 android_atomic_add(int32_t increment, volatile int32_t *ptr)
 {
     int32_t prev, status;
diff --git a/include/cutils/atomic-mips64.h b/include/cutils/atomic-mips64.h
new file mode 100644
index 0000000..99bbe3a
--- /dev/null
+++ b/include/cutils/atomic-mips64.h
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_CUTILS_ATOMIC_MIPS64_H
+#define ANDROID_CUTILS_ATOMIC_MIPS64_H
+
+#include <stdint.h>
+
+#ifndef ANDROID_ATOMIC_INLINE
+#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline))
+#endif
+
+extern ANDROID_ATOMIC_INLINE void android_compiler_barrier(void)
+{
+    __asm__ __volatile__ ("" : : : "memory");
+}
+
+#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();
+}
+#else
+extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
+{
+    __asm__ __volatile__ ("sync" : : : "memory");
+}
+extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
+{
+    __asm__ __volatile__ ("sync" : : : "memory");
+}
+#endif
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
+{
+    int32_t value = *ptr;
+    android_memory_barrier();
+    return value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_acquire_load64(volatile const int64_t *ptr)
+{
+    int64_t value = *ptr;
+    android_memory_barrier();
+    return value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_release_load(volatile const int32_t *ptr)
+{
+    android_memory_barrier();
+    return *ptr;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_release_load64(volatile const int64_t *ptr)
+{
+    android_memory_barrier();
+    return *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_acquire_store64(int64_t value, volatile int64_t *ptr)
+{
+    *ptr = value;
+    android_memory_barrier();
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_release_store(int32_t value, volatile int32_t *ptr)
+{
+    android_memory_barrier();
+    *ptr = value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_release_store64(int64_t value, volatile int64_t *ptr)
+{
+    android_memory_barrier();
+    *ptr = value;
+}
+
+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__ (
+            "    ll     %[prev], (%[ptr])\n"
+            "    li     %[status], 1\n"
+            "    bne    %[prev], %[old], 9f\n"
+            "    move   %[status], %[new_value]\n"
+            "    sc     %[status], (%[ptr])\n"
+            "9:\n"
+            : [prev] "=&r" (prev), [status] "=&r" (status)
+            : [ptr] "r" (ptr), [old] "r" (old_value), [new_value] "r" (new_value)
+            );
+    } while (__builtin_expect(status == 0, 0));
+    return prev != old_value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_cas64(int64_t old_value, int64_t new_value,
+                             volatile int64_t *ptr)
+{
+    return __sync_val_compare_and_swap(ptr, old_value, new_value) != old_value;
+}
+
+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
+int64_t android_atomic_acquire_cas64(int64_t old_value, int64_t new_value,
+                                     volatile int64_t *ptr)
+{
+    int status = android_atomic_cas64(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)
+{
+    android_memory_barrier();
+    return android_atomic_cas(old_value, new_value, ptr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_release_cas64(int64_t old_value, int64_t new_value,
+                                     volatile int64_t *ptr)
+{
+    android_memory_barrier();
+    return android_atomic_cas64(old_value, new_value, ptr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr)
+{
+    int32_t prev, status;
+    android_memory_barrier();
+    do {
+        __asm__ __volatile__ (
+        "    ll    %[prev], (%[ptr])\n"
+        "    addu  %[status], %[prev], %[inc]\n"
+        "    sc    %[status], (%[ptr])\n"
+        :  [status] "=&r" (status), [prev] "=&r" (prev)
+        :  [ptr] "r" (ptr), [inc] "Ir" (increment)
+        );
+    } while (__builtin_expect(status == 0, 0));
+    return prev;
+}
+
+extern ANDROID_ATOMIC_INLINE int32_t
+android_atomic_inc(volatile int32_t *addr)
+{
+    return android_atomic_add(1, addr);
+}
+
+extern ANDROID_ATOMIC_INLINE int32_t
+android_atomic_dec(volatile int32_t *addr)
+{
+    return android_atomic_add(-1, addr);
+}
+
+extern ANDROID_ATOMIC_INLINE int32_t
+android_atomic_and(int32_t value, volatile int32_t *ptr)
+{
+    int32_t prev, status;
+    android_memory_barrier();
+    do {
+        __asm__ __volatile__ (
+        "    ll    %[prev], (%[ptr])\n"
+        "    and   %[status], %[prev], %[value]\n"
+        "    sc    %[status], (%[ptr])\n"
+        : [prev] "=&r" (prev), [status] "=&r" (status)
+        : [ptr] "r" (ptr), [value] "Ir" (value)
+            );
+    } while (__builtin_expect(status == 0, 0));
+    return prev;
+}
+
+extern ANDROID_ATOMIC_INLINE int32_t
+android_atomic_or(int32_t value, volatile int32_t *ptr)
+{
+    int32_t prev, status;
+    android_memory_barrier();
+    do {
+        __asm__ __volatile__ (
+        "    ll    %[prev], (%[ptr])\n"
+        "    or    %[status], %[prev], %[value]\n"
+        "    sc    %[status], (%[ptr])\n"
+        : [prev] "=&r" (prev), [status] "=&r" (status)
+        : [ptr] "r" (ptr), [value] "Ir" (value)
+            );
+    } while (__builtin_expect(status == 0, 0));
+    return prev;
+}
+
+#endif /* ANDROID_CUTILS_ATOMIC_MIPS_H */
diff --git a/include/cutils/atomic-x86_64.h b/include/cutils/atomic-x86_64.h
new file mode 100644
index 0000000..5b5c203
--- /dev/null
+++ b/include/cutils/atomic-x86_64.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2014 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.
+ *
+ * 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.
+ */
+
+#ifndef ANDROID_CUTILS_ATOMIC_X86_64_H
+#define ANDROID_CUTILS_ATOMIC_X86_64_H
+
+#include <stdint.h>
+
+#ifndef ANDROID_ATOMIC_INLINE
+#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline))
+#endif
+
+extern ANDROID_ATOMIC_INLINE
+void android_compiler_barrier(void)
+{
+    __asm__ __volatile__ ("" : : : "memory");
+}
+
+#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();
+}
+#else
+extern ANDROID_ATOMIC_INLINE
+void android_memory_barrier(void)
+{
+    __asm__ __volatile__ ("mfence" : : : "memory");
+}
+extern ANDROID_ATOMIC_INLINE
+void android_memory_store_barrier(void)
+{
+    android_compiler_barrier();
+}
+#endif
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
+{
+    int32_t value = *ptr;
+    android_compiler_barrier();
+    return value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_acquire_load64(volatile const int64_t *ptr)
+{
+    int64_t value = *ptr;
+    android_compiler_barrier();
+    return value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_release_load(volatile const int32_t *ptr)
+{
+    android_memory_barrier();
+    return *ptr;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_release_load64(volatile const int64_t *ptr)
+{
+    android_memory_barrier();
+    return *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_acquire_store64(int64_t value, volatile int64_t *ptr)
+{
+    *ptr = value;
+    android_memory_barrier();
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_release_store(int32_t value, volatile int32_t *ptr)
+{
+    android_compiler_barrier();
+    *ptr = value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_release_store64(int64_t value, volatile int64_t *ptr)
+{
+    android_compiler_barrier();
+    *ptr = value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_cas(int32_t old_value, int32_t new_value,
+                       volatile int32_t *ptr)
+{
+    int32_t prev;
+    __asm__ __volatile__ ("lock; cmpxchgl %1, %2"
+                          : "=a" (prev)
+                          : "q" (new_value), "m" (*ptr), "0" (old_value)
+                          : "memory");
+    return prev != old_value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_cas64(int64_t old_value, int64_t new_value,
+                             volatile int64_t *ptr)
+{
+    int64_t prev;
+    __asm__ __volatile__ ("lock; cmpxchgq %1, %2"
+                          : "=a" (prev)
+                          : "q" (new_value), "m" (*ptr), "0" (old_value)
+                          : "memory");
+    return prev != old_value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_acquire_cas(int32_t old_value, int32_t new_value,
+                               volatile int32_t *ptr)
+{
+    /* Loads are not reordered with other loads. */
+    return android_atomic_cas(old_value, new_value, ptr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_acquire_cas64(int64_t old_value, int64_t new_value,
+                                     volatile int64_t *ptr)
+{
+    /* Loads are not reordered with other loads. */
+    return android_atomic_cas64(old_value, new_value, ptr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_release_cas(int32_t old_value, int32_t new_value,
+                               volatile int32_t *ptr)
+{
+    /* Stores are not reordered with other stores. */
+    return android_atomic_cas(old_value, new_value, ptr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_release_cas64(int64_t old_value, int64_t new_value,
+                                     volatile int64_t *ptr)
+{
+    /* Stores are not reordered with other stores. */
+    return android_atomic_cas64(old_value, new_value, ptr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr)
+{
+    __asm__ __volatile__ ("lock; xaddl %0, %1"
+                          : "+r" (increment), "+m" (*ptr)
+                          : : "memory");
+    /* increment now holds the old value of *ptr */
+    return increment;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_inc(volatile int32_t *addr)
+{
+    return android_atomic_add(1, addr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_dec(volatile int32_t *addr)
+{
+    return android_atomic_add(-1, addr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_and(int32_t value, volatile int32_t *ptr)
+{
+    int32_t prev, status;
+    do {
+        prev = *ptr;
+        status = android_atomic_cas(prev, prev & value, ptr);
+    } while (__builtin_expect(status != 0, 0));
+    return prev;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_or(int32_t value, volatile int32_t *ptr)
+{
+    int32_t prev, status;
+    do {
+        prev = *ptr;
+        status = android_atomic_cas(prev, prev | value, ptr);
+    } while (__builtin_expect(status != 0, 0));
+    return prev;
+}
+
+#endif /* ANDROID_CUTILS_ATOMIC_X86_64_H */
diff --git a/include/cutils/bitops.h b/include/cutils/bitops.h
index c26dc54..045830d 100644
--- a/include/cutils/bitops.h
+++ b/include/cutils/bitops.h
@@ -59,7 +59,7 @@
 static inline int bitmask_ffz(unsigned int *bitmask, int num_bits)
 {
     int bit, result;
-    unsigned int i;
+    size_t i;
 
     for (i = 0; i < BITS_TO_WORDS(num_bits); i++) {
         bit = ffs(~bitmask[i]);
@@ -77,7 +77,7 @@
 
 static inline int bitmask_weight(unsigned int *bitmask, int num_bits)
 {
-    int i;
+    size_t i;
     int weight = 0;
 
     for (i = 0; i < BITS_TO_WORDS(num_bits); i++)
diff --git a/include/cutils/debugger.h b/include/cutils/debugger.h
index 4eda523..ae6bfc4 100644
--- a/include/cutils/debugger.h
+++ b/include/cutils/debugger.h
@@ -23,7 +23,11 @@
 extern "C" {
 #endif
 
+#if __LP64__
+#define DEBUGGER_SOCKET_NAME "android:debuggerd64"
+#else
 #define DEBUGGER_SOCKET_NAME "android:debuggerd"
+#endif
 
 typedef enum {
     // dump a crash
@@ -38,6 +42,7 @@
     debugger_action_t action;
     pid_t tid;
     uintptr_t abort_msg_address;
+    int32_t original_si_code;
 } debugger_msg_t;
 
 /* Dumps a process backtrace, registers, and stack to a tombstone file (requires root).
diff --git a/include/cutils/fs.h b/include/cutils/fs.h
index d1d4cf2..70f0b92 100644
--- a/include/cutils/fs.h
+++ b/include/cutils/fs.h
@@ -18,6 +18,7 @@
 #define __CUTILS_FS_H
 
 #include <sys/types.h>
+#include <unistd.h>
 
 /*
  * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
diff --git a/include/cutils/klog.h b/include/cutils/klog.h
index ba728ac..3635e89 100644
--- a/include/cutils/klog.h
+++ b/include/cutils/klog.h
@@ -18,22 +18,31 @@
 #define _CUTILS_KLOG_H_
 
 #include <sys/cdefs.h>
+#include <stdarg.h>
 
 __BEGIN_DECLS
 
 void klog_init(void);
+int  klog_get_level(void);
 void klog_set_level(int level);
 void klog_close(void);
 void klog_write(int level, const char *fmt, ...)
     __attribute__ ((format(printf, 2, 3)));
+void klog_vwrite(int level, const char *fmt, va_list ap);
 
 __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)
-#define KLOG_INFO(tag,x...)    klog_write(6, "<6>" tag ": " x)
-#define KLOG_DEBUG(tag,x...)   klog_write(7, "<7>" tag ": " x)
+#define KLOG_ERROR_LEVEL   3
+#define KLOG_WARNING_LEVEL 4
+#define KLOG_NOTICE_LEVEL  5
+#define KLOG_INFO_LEVEL    6
+#define KLOG_DEBUG_LEVEL   7
+
+#define KLOG_ERROR(tag,x...)   klog_write(KLOG_ERROR_LEVEL, "<3>" tag ": " x)
+#define KLOG_WARNING(tag,x...) klog_write(KLOG_WARNING_LEVEL, "<4>" tag ": " x)
+#define KLOG_NOTICE(tag,x...)  klog_write(KLOG_NOTICE_LEVEL, "<5>" tag ": " x)
+#define KLOG_INFO(tag,x...)    klog_write(KLOG_INFO_LEVEL, "<6>" tag ": " x)
+#define KLOG_DEBUG(tag,x...)   klog_write(KLOG_DEBUG_LEVEL, "<7>" tag ": " x)
 
 #define KLOG_DEFAULT_LEVEL  3  /* messages <= this level are logged */
 
diff --git a/include/cutils/list.h b/include/cutils/list.h
index 945729a..4ba2cfd 100644
--- a/include/cutils/list.h
+++ b/include/cutils/list.h
@@ -44,10 +44,10 @@
 #define list_for_each_reverse(node, list) \
     for (node = (list)->prev; node != (list); node = node->prev)
 
-#define list_for_each_safe(node, next, list) \
-    for (node = (list)->next, next = node->next; \
+#define list_for_each_safe(node, n, list) \
+    for (node = (list)->next, n = node->next; \
          node != (list); \
-         node = next, next = node->next)
+         node = n, n = node->next)
 
 static inline void list_init(struct listnode *node)
 {
@@ -63,6 +63,14 @@
     head->prev = item;
 }
 
+static inline void list_add_head(struct listnode *head, struct listnode *item)
+{
+    item->next = head->next;
+    item->prev = head;
+    head->next->prev = item;
+    head->next = item;
+}
+
 static inline void list_remove(struct listnode *item)
 {
     item->next->prev = item->prev;
diff --git a/include/cutils/misc.h b/include/cutils/misc.h
index 2c48dfa..0de505f 100644
--- a/include/cutils/misc.h
+++ b/include/cutils/misc.h
@@ -28,13 +28,6 @@
          */
 extern void *load_file(const char *fn, unsigned *sz);
 
-        /* Connects your process to the system debugger daemon
-         * so that on a crash it may be logged or interactively
-         * debugged (depending on system settings).
-         */
-extern void debuggerd_connect(void);
-
-
         /* This is the range of UIDs (and GIDs) that are reserved
          * for assigning to applications.
          */
diff --git a/include/cutils/properties.h b/include/cutils/properties.h
index 2c70165..798db8b 100644
--- a/include/cutils/properties.h
+++ b/include/cutils/properties.h
@@ -20,6 +20,7 @@
 #include <sys/cdefs.h>
 #include <stddef.h>
 #include <sys/system_properties.h>
+#include <stdint.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -44,6 +45,64 @@
 */
 int property_get(const char *key, char *value, const char *default_value);
 
+/* property_get_bool: returns the value of key coerced into a
+** boolean. If the property is not set, then the default value is returned.
+**
+* The following is considered to be true (1):
+**   "1", "true", "y", "yes", "on"
+**
+** The following is considered to be false (0):
+**   "0", "false", "n", "no", "off"
+**
+** The conversion is whitespace-sensitive (e.g. " off" will not be false).
+**
+** If no property with this key is set (or the key is NULL) or the boolean
+** conversion fails, the default value is returned.
+**/
+int8_t property_get_bool(const char *key, int8_t default_value);
+
+/* property_get_int64: returns the value of key truncated and coerced into a
+** int64_t. If the property is not set, then the default value is used.
+**
+** The numeric conversion is identical to strtoimax with the base inferred:
+** - All digits up to the first non-digit characters are read
+** - The longest consecutive prefix of digits is converted to a long
+**
+** Valid strings of digits are:
+** - An optional sign character + or -
+** - An optional prefix indicating the base (otherwise base 10 is assumed)
+**   -- 0 prefix is octal
+**   -- 0x / 0X prefix is hex
+**
+** Leading/trailing whitespace is ignored. Overflow/underflow will cause
+** numeric conversion to fail.
+**
+** If no property with this key is set (or the key is NULL) or the numeric
+** conversion fails, the default value is returned.
+**/
+int64_t property_get_int64(const char *key, int64_t default_value);
+
+/* property_get_int32: returns the value of key truncated and coerced into an
+** int32_t. If the property is not set, then the default value is used.
+**
+** The numeric conversion is identical to strtoimax with the base inferred:
+** - All digits up to the first non-digit characters are read
+** - The longest consecutive prefix of digits is converted to a long
+**
+** Valid strings of digits are:
+** - An optional sign character + or -
+** - An optional prefix indicating the base (otherwise base 10 is assumed)
+**   -- 0 prefix is octal
+**   -- 0x / 0X prefix is hex
+**
+** Leading/trailing whitespace is ignored. Overflow/underflow will cause
+** numeric conversion to fail.
+**
+** If no property with this key is set (or the key is NULL) or the numeric
+** conversion fails, the default value is returned.
+**/
+int32_t property_get_int32(const char *key, int32_t default_value);
+
 /* property_set: returns 0 on success, < 0 on failure
 */
 int property_set(const char *key, const char *value);
diff --git a/include/cutils/sockets.h b/include/cutils/sockets.h
index 19cae0c..daf43ec 100644
--- a/include/cutils/sockets.h
+++ b/include/cutils/sockets.h
@@ -86,6 +86,8 @@
 
 extern int socket_loopback_client(int port, int type);
 extern int socket_network_client(const char *host, int port, int type);
+extern int socket_network_client_timeout(const char *host, int port, int type,
+                                         int timeout);
 extern int socket_loopback_server(int port, int type);
 extern int socket_local_server(const char *name, int namespaceId, int type);
 extern int socket_local_server_bind(int s, const char *name, int namespaceId);
diff --git a/include/cutils/trace.h b/include/cutils/trace.h
index 1c8f107..fd9bc6a 100644
--- a/include/cutils/trace.h
+++ b/include/cutils/trace.h
@@ -17,13 +17,15 @@
 #ifndef _LIBS_CUTILS_TRACE_H
 #define _LIBS_CUTILS_TRACE_H
 
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
 #include <sys/cdefs.h>
 #include <sys/types.h>
-#include <stdint.h>
-#include <stdbool.h>
 #include <unistd.h>
-#include <cutils/compiler.h>
 
+#include <cutils/compiler.h>
 #ifdef ANDROID_SMP
 #include <cutils/atomic-inline.h>
 #else
@@ -67,7 +69,8 @@
 #define ATRACE_TAG_RESOURCES        (1<<13)
 #define ATRACE_TAG_DALVIK           (1<<14)
 #define ATRACE_TAG_RS               (1<<15)
-#define ATRACE_TAG_LAST             ATRACE_TAG_RS
+#define ATRACE_TAG_BIONIC           (1<<16)
+#define ATRACE_TAG_LAST             ATRACE_TAG_BIONIC
 
 // Reserved for initialization.
 #define ATRACE_TAG_NOT_READY        (1LL<<63)
@@ -217,8 +220,8 @@
         char buf[ATRACE_MESSAGE_LENGTH];
         size_t len;
 
-        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "S|%d|%s|%d", getpid(),
-                name, cookie);
+        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "S|%d|%s|%" PRId32,
+                getpid(), name, cookie);
         write(atrace_marker_fd, buf, len);
     }
 }
@@ -235,8 +238,8 @@
         char buf[ATRACE_MESSAGE_LENGTH];
         size_t len;
 
-        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "F|%d|%s|%d", getpid(),
-                name, cookie);
+        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "F|%d|%s|%" PRId32,
+                getpid(), name, cookie);
         write(atrace_marker_fd, buf, len);
     }
 }
@@ -253,7 +256,7 @@
         char buf[ATRACE_MESSAGE_LENGTH];
         size_t len;
 
-        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%d",
+        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%" PRId32,
                 getpid(), name, value);
         write(atrace_marker_fd, buf, len);
     }
@@ -270,7 +273,7 @@
         char buf[ATRACE_MESSAGE_LENGTH];
         size_t len;
 
-        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%lld",
+        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%" PRId64,
                 getpid(), name, value);
         write(atrace_marker_fd, buf, len);
     }
diff --git a/include/log/log.h b/include/log/log.h
index 7f952ff..ace12d6 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -73,10 +73,11 @@
  * Simplified macro to send a verbose log message using the current LOG_TAG.
  */
 #ifndef ALOGV
+#define __ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
 #if LOG_NDEBUG
-#define ALOGV(...)   ((void)0)
+#define ALOGV(...) do { if (0) { __ALOGV(__VA_ARGS__); } } while (0)
 #else
-#define ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#define ALOGV(...) __ALOGV(__VA_ARGS__)
 #endif
 #endif
 
@@ -202,10 +203,11 @@
  * Simplified macro to send a verbose system log message using the current LOG_TAG.
  */
 #ifndef SLOGV
+#define __SLOGV(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
 #if LOG_NDEBUG
-#define SLOGV(...)   ((void)0)
+#define SLOGV(...) do { if (0) { __SLOGV(__VA_ARGS__); } } while (0)
 #else
-#define SLOGV(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#define SLOGV(...) __SLOGV(__VA_ARGS__)
 #endif
 #endif
 
@@ -284,10 +286,11 @@
  * Simplified macro to send a verbose radio log message using the current LOG_TAG.
  */
 #ifndef RLOGV
+#define __RLOGV(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
 #if LOG_NDEBUG
-#define RLOGV(...)   ((void)0)
+#define RLOGV(...) do { if (0) { __RLOGV(__VA_ARGS__); } } while (0)
 #else
-#define RLOGV(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#define RLOGV(...) __RLOGV(__VA_ARGS__)
 #endif
 #endif
 
@@ -488,7 +491,7 @@
 #endif
 #ifndef LOG_EVENT_STRING
 #define LOG_EVENT_STRING(_tag, _value)                                      \
-    ((void) 0)  /* not implemented -- must combine len with string */
+        (void) __android_log_bswrite(_tag, _value);
 #endif
 /* TODO: something for LIST */
 
@@ -547,6 +550,7 @@
     LOG_ID_RADIO = 1,
     LOG_ID_EVENTS = 2,
     LOG_ID_SYSTEM = 3,
+    LOG_ID_CRASH = 4,
 
     LOG_ID_MAX
 } log_id_t;
@@ -557,7 +561,11 @@
  * Send a simple string to the log.
  */
 int __android_log_buf_write(int bufID, int prio, const char *tag, const char *text);
-int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...);
+int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...)
+#if defined(__GNUC__)
+    __attribute__((__format__(printf, 4, 5)))
+#endif
+    ;
 
 #ifdef __cplusplus
 }
diff --git a/include/log/log_read.h b/include/log/log_read.h
index 861c192..946711a 100644
--- a/include/log/log_read.h
+++ b/include/log/log_read.h
@@ -17,23 +17,45 @@
 #ifndef _LIBS_LOG_LOG_READ_H
 #define _LIBS_LOG_LOG_READ_H
 
+#include <stdint.h>
 #include <time.h>
 
+/* struct log_time is a wire-format variant of struct timespec */
 #define NS_PER_SEC 1000000000ULL
+
 #ifdef __cplusplus
-struct log_time : public timespec {
+
+// NB: do NOT define a copy constructor. This will result in structure
+// no longer being compatible with pass-by-value which is desired
+// efficient behavior. Also, pass-by-reference breaks C/C++ ABI.
+struct log_time {
 public:
-    log_time(timespec &T)
+    uint32_t tv_sec; // good to Feb 5 2106
+    uint32_t tv_nsec;
+
+    static const uint32_t tv_sec_max = 0xFFFFFFFFUL;
+    static const uint32_t tv_nsec_max = 999999999UL;
+
+    log_time(const timespec &T)
     {
         tv_sec = T.tv_sec;
         tv_nsec = T.tv_nsec;
     }
-    log_time(void)
+    log_time(uint32_t sec, uint32_t nsec)
+    {
+        tv_sec = sec;
+        tv_nsec = nsec;
+    }
+    static const timespec EPOCH;
+    log_time()
     {
     }
     log_time(clockid_t id)
     {
-        clock_gettime(id, (timespec *) this);
+        timespec T;
+        clock_gettime(id, &T);
+        tv_sec = T.tv_sec;
+        tv_nsec = T.tv_nsec;
     }
     log_time(const char *T)
     {
@@ -41,9 +63,12 @@
         tv_sec = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
         tv_nsec = c[4] | (c[5] << 8) | (c[6] << 16) | (c[7] << 24);
     }
+
+    // timespec
     bool operator== (const timespec &T) const
     {
-        return (tv_sec == T.tv_sec) && (tv_nsec == T.tv_nsec);
+        return (tv_sec == static_cast<uint32_t>(T.tv_sec))
+            && (tv_nsec == static_cast<uint32_t>(T.tv_nsec));
     }
     bool operator!= (const timespec &T) const
     {
@@ -51,8 +76,9 @@
     }
     bool operator< (const timespec &T) const
     {
-        return (tv_sec < T.tv_sec)
-            || ((tv_sec == T.tv_sec) && (tv_nsec < T.tv_nsec));
+        return (tv_sec < static_cast<uint32_t>(T.tv_sec))
+            || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
+                && (tv_nsec < static_cast<uint32_t>(T.tv_nsec)));
     }
     bool operator>= (const timespec &T) const
     {
@@ -60,20 +86,73 @@
     }
     bool operator> (const timespec &T) const
     {
-        return (tv_sec > T.tv_sec)
-            || ((tv_sec == T.tv_sec) && (tv_nsec > T.tv_nsec));
+        return (tv_sec > static_cast<uint32_t>(T.tv_sec))
+            || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
+                && (tv_nsec > static_cast<uint32_t>(T.tv_nsec)));
     }
     bool operator<= (const timespec &T) const
     {
         return !(*this > T);
     }
-    uint64_t nsec(void) const
+    log_time operator-= (const timespec &T);
+    log_time operator- (const timespec &T) const
+    {
+        log_time local(*this);
+        return local -= T;
+    }
+
+    // log_time
+    bool operator== (const log_time &T) const
+    {
+        return (tv_sec == T.tv_sec) && (tv_nsec == T.tv_nsec);
+    }
+    bool operator!= (const log_time &T) const
+    {
+        return !(*this == T);
+    }
+    bool operator< (const log_time &T) const
+    {
+        return (tv_sec < T.tv_sec)
+            || ((tv_sec == T.tv_sec) && (tv_nsec < T.tv_nsec));
+    }
+    bool operator>= (const log_time &T) const
+    {
+        return !(*this < T);
+    }
+    bool operator> (const log_time &T) const
+    {
+        return (tv_sec > T.tv_sec)
+            || ((tv_sec == T.tv_sec) && (tv_nsec > T.tv_nsec));
+    }
+    bool operator<= (const log_time &T) const
+    {
+        return !(*this > T);
+    }
+    log_time operator-= (const log_time &T);
+    log_time operator- (const log_time &T) const
+    {
+        log_time local(*this);
+        return local -= T;
+    }
+
+    uint64_t nsec() const
     {
         return static_cast<uint64_t>(tv_sec) * NS_PER_SEC + tv_nsec;
     }
-};
+
+    static const char default_format[];
+
+    // Add %#q for the fraction of a second to the standard library functions
+    char *strptime(const char *s, const char *format = default_format);
+} __attribute__((__packed__));
+
 #else
-typedef struct timespec log_time;
+
+typedef struct log_time {
+    uint32_t tv_sec;
+    uint32_t tv_nsec;
+} __attribute__((__packed__)) log_time;
+
 #endif
 
 #endif /* define _LIBS_LOG_LOG_READ_H */
diff --git a/include/log/logd.h b/include/log/logd.h
index 379c373..2e6f220 100644
--- a/include/log/logd.h
+++ b/include/log/logd.h
@@ -41,6 +41,7 @@
 int __android_log_bwrite(int32_t tag, const void *payload, size_t len);
 int __android_log_btwrite(int32_t tag, char type, const void *payload,
     size_t len);
+int __android_log_bswrite(int32_t tag, const char *payload);
 
 #ifdef __cplusplus
 }
diff --git a/include/log/logger.h b/include/log/logger.h
index 966397a..53be1d3 100644
--- a/include/log/logger.h
+++ b/include/log/logger.h
@@ -12,6 +12,7 @@
 
 #include <stdint.h>
 #include <log/log.h>
+#include <log/log_read.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -30,12 +31,12 @@
     int32_t     sec;    /* seconds since Epoch */
     int32_t     nsec;   /* nanoseconds */
     char        msg[0]; /* the entry's payload */
-};
+} __attribute__((__packed__));
 
 /*
  * The userspace structure for version 2 of the logger_entry ABI.
  * This structure is returned to userspace if ioctl(LOGGER_SET_VERSION)
- * is called with version==2
+ * is called with version==2; or used with the user space log daemon.
  */
 struct logger_entry_v2 {
     uint16_t    len;       /* length of the payload */
@@ -46,13 +47,23 @@
     int32_t     nsec;      /* nanoseconds */
     uint32_t    euid;      /* effective UID of logger */
     char        msg[0];    /* the entry's payload */
-};
+} __attribute__((__packed__));
+
+struct logger_entry_v3 {
+    uint16_t    len;       /* length of the payload */
+    uint16_t    hdr_size;  /* sizeof(struct logger_entry_v3) */
+    int32_t     pid;       /* generating process's pid */
+    int32_t     tid;       /* generating process's tid */
+    int32_t     sec;       /* seconds since Epoch */
+    int32_t     nsec;      /* nanoseconds */
+    uint32_t    lid;       /* log id of the payload */
+    char        msg[0];    /* the entry's payload */
+} __attribute__((__packed__));
 
 /*
  * The maximum size of the log entry payload that can be
- * written to the kernel logger driver. An attempt to write
- * more than this amount to /dev/log/* will result in a
- * truncated log entry.
+ * written to the logger. An attempt to write more than
+ * this amount will result in a truncated log entry.
  */
 #define LOGGER_ENTRY_MAX_PAYLOAD	4076
 
@@ -68,13 +79,10 @@
 struct log_msg {
     union {
         unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
-        struct logger_entry_v2 entry;
+        struct logger_entry_v3 entry;
+        struct logger_entry_v3 entry_v3;
         struct logger_entry_v2 entry_v2;
         struct logger_entry    entry_v1;
-        struct {
-            unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
-            log_id_t id;
-        } extra;
     } __attribute__((aligned(4)));
 #ifdef __cplusplus
     /* Matching log_time operators */
@@ -106,21 +114,21 @@
     {
         return !(*this > T);
     }
-    uint64_t nsec(void) const
+    uint64_t nsec() const
     {
         return static_cast<uint64_t>(entry.sec) * NS_PER_SEC + entry.nsec;
     }
 
     /* packet methods */
-    log_id_t id(void)
+    log_id_t id()
     {
-        return extra.id;
+        return (log_id_t) entry.lid;
     }
-    char *msg(void)
+    char *msg()
     {
         return entry.hdr_size ? (char *) buf + entry.hdr_size : entry_v1.msg;
     }
-    unsigned int len(void)
+    unsigned int len()
     {
         return (entry.hdr_size ? entry.hdr_size : sizeof(entry_v1)) + entry.len;
     }
@@ -132,15 +140,26 @@
 log_id_t android_logger_get_id(struct logger *logger);
 
 int android_logger_clear(struct logger *logger);
-int android_logger_get_log_size(struct logger *logger);
-int android_logger_get_log_readable_size(struct logger *logger);
+long android_logger_get_log_size(struct logger *logger);
+int android_logger_set_log_size(struct logger *logger, unsigned long size);
+long android_logger_get_log_readable_size(struct logger *logger);
 int android_logger_get_log_version(struct logger *logger);
 
 struct logger_list;
 
+ssize_t android_logger_get_statistics(struct logger_list *logger_list,
+                                      char *buf, size_t len);
+ssize_t android_logger_get_prune_list(struct logger_list *logger_list,
+                                      char *buf, size_t len);
+int android_logger_set_prune_list(struct logger_list *logger_list,
+                                  char *buf, size_t len);
+
 struct logger_list *android_logger_list_alloc(int mode,
                                               unsigned int tail,
                                               pid_t pid);
+struct logger_list *android_logger_list_alloc_time(int mode,
+                                                   log_time start,
+                                                   pid_t pid);
 void android_logger_list_free(struct logger_list *logger_list);
 /* In the purest sense, the following two are orthogonal interfaces */
 int android_logger_list_read(struct logger_list *logger_list,
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 0ed0d78..d8e938e 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -76,6 +76,8 @@
 #define AID_SDCARD_PICS   1033  /* external storage photos access */
 #define AID_SDCARD_AV     1034  /* external storage audio/video access */
 #define AID_SDCARD_ALL    1035  /* access all users external storage */
+#define AID_LOGD          1036  /* log daemon */
+#define AID_SHARED_RELRO  1037  /* creator of shared GNU RELRO files */
 
 #define AID_SHELL         2000  /* adb and debug shell user */
 #define AID_CACHE         2001  /* cache access */
@@ -92,6 +94,7 @@
 #define AID_NET_BW_ACCT   3007  /* change bandwidth statistics accounting */
 #define AID_NET_BT_STACK  3008  /* bluetooth: access config files */
 
+#define AID_EVERYBODY     9997  /* shared between all apps in the same profile */
 #define AID_MISC          9998  /* access to misc storage */
 #define AID_NOBODY        9999
 
@@ -151,6 +154,8 @@
     { "sdcard_pics",   AID_SDCARD_PICS, },
     { "sdcard_av",     AID_SDCARD_AV, },
     { "sdcard_all",    AID_SDCARD_ALL, },
+    { "logd",          AID_LOGD, },
+    { "shared_relro",  AID_SHARED_RELRO, },
 
     { "shell",         AID_SHELL, },
     { "cache",         AID_CACHE, },
@@ -165,6 +170,7 @@
     { "net_bw_acct",   AID_NET_BW_ACCT, },
     { "net_bt_stack",  AID_NET_BT_STACK, },
 
+    { "everybody",     AID_EVERYBODY, },
     { "misc",          AID_MISC, },
     { "nobody",        AID_NOBODY, },
 };
@@ -196,6 +202,7 @@
     { 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" },
+    { 00771, AID_SHARED_RELRO, AID_SHARED_RELRO, 0, "data/misc/shared_relro" },
     { 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" },
@@ -237,7 +244,7 @@
 
     /* 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" },
+    { 04750, AID_ROOT,      AID_SHELL,     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" },
@@ -249,6 +256,7 @@
 
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/*" },
     { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib/valgrind/*" },
+    { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib64/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/*" },
diff --git a/include/system/audio.h b/include/system/audio.h
index aa7ac02..8838e71 100644
--- a/include/system/audio.h
+++ b/include/system/audio.h
@@ -434,6 +434,14 @@
 static const audio_offload_info_t AUDIO_INFO_INITIALIZER = {
     version: AUDIO_OFFLOAD_INFO_VERSION_CURRENT,
     size: sizeof(audio_offload_info_t),
+    sample_rate: 0,
+    channel_mask: 0,
+    format: AUDIO_FORMAT_DEFAULT,
+    stream_type: AUDIO_STREAM_VOICE_CALL,
+    bit_rate: 0,
+    duration_us: 0,
+    has_video: false,
+    is_streaming: false
 };
 
 static inline bool audio_is_output_device(audio_devices_t device)
@@ -471,12 +479,16 @@
 
 static inline bool audio_is_bluetooth_sco_device(audio_devices_t device)
 {
-    device &= ~AUDIO_DEVICE_BIT_IN;
-    if ((popcount(device) == 1) && (device & (AUDIO_DEVICE_OUT_ALL_SCO |
-                   AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)))
-        return true;
-    else
-        return false;
+    if ((device & AUDIO_DEVICE_BIT_IN) == 0) {
+        if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_OUT_ALL_SCO) == 0))
+            return true;
+    } else {
+        device &= ~AUDIO_DEVICE_BIT_IN;
+        if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) == 0))
+            return true;
+    }
+
+    return false;
 }
 
 static inline bool audio_is_usb_device(audio_devices_t device)
diff --git a/include/system/window.h b/include/system/window.h
index 588f9c6..31f202f 100644
--- a/include/system/window.h
+++ b/include/system/window.h
@@ -26,6 +26,13 @@
 #include <system/graphics.h>
 #include <unistd.h>
 
+#ifndef __UNUSED
+#define __UNUSED __attribute__((__unused__))
+#endif
+#ifndef __deprecated
+#define __deprecated __attribute__((__deprecated__))
+#endif
+
 __BEGIN_DECLS
 
 /*****************************************************************************/
@@ -89,10 +96,10 @@
 
     // Implement the methods that sp<ANativeWindowBuffer> expects so that it
     // can be used to automatically refcount ANativeWindowBuffer's.
-    void incStrong(const void* id) const {
+    void incStrong(const void* /*id*/) const {
         common.incRef(const_cast<android_native_base_t*>(&common));
     }
-    void decStrong(const void* id) const {
+    void decStrong(const void* /*id*/) const {
         common.decRef(const_cast<android_native_base_t*>(&common));
     }
 #endif
@@ -352,10 +359,10 @@
 
     /* Implement the methods that sp<ANativeWindow> expects so that it
        can be used to automatically refcount ANativeWindow's. */
-    void incStrong(const void* id) const {
+    void incStrong(const void* /*id*/) const {
         common.incRef(const_cast<android_native_base_t*>(&common));
     }
-    void decStrong(const void* id) const {
+    void decStrong(const void* /*id*/) const {
         common.decRef(const_cast<android_native_base_t*>(&common));
     }
 #endif
@@ -582,7 +589,7 @@
   * android_native_window_t is deprecated.
   */
 typedef struct ANativeWindow ANativeWindow;
-typedef struct ANativeWindow android_native_window_t;
+typedef struct ANativeWindow android_native_window_t __deprecated;
 
 /*
  *  native_window_set_usage(..., usage)
@@ -603,13 +610,19 @@
 
 /* deprecated. Always returns 0. Don't call. */
 static inline int native_window_connect(
-        struct ANativeWindow* window, int api) {
+        struct ANativeWindow* window __UNUSED, int api __UNUSED) __deprecated;
+
+static inline int native_window_connect(
+        struct ANativeWindow* window __UNUSED, int api __UNUSED) {
     return 0;
 }
 
 /* deprecated. Always returns 0. Don't call. */
 static inline int native_window_disconnect(
-        struct ANativeWindow* window, int api) {
+        struct ANativeWindow* window __UNUSED, int api __UNUSED) __deprecated;
+
+static inline int native_window_disconnect(
+        struct ANativeWindow* window __UNUSED, int api __UNUSED) {
     return 0;
 }
 
@@ -664,6 +677,10 @@
  */
 static inline int native_window_set_active_rect(
         struct ANativeWindow* window,
+        android_native_rect_t const * active_rect) __deprecated;
+
+static inline int native_window_set_active_rect(
+        struct ANativeWindow* window,
         android_native_rect_t const * active_rect)
 {
     return native_window_set_post_transform_crop(window, active_rect);
@@ -691,6 +708,10 @@
  */
 static inline int native_window_set_buffers_geometry(
         struct ANativeWindow* window,
+        int w, int h, int format) __deprecated;
+
+static inline int native_window_set_buffers_geometry(
+        struct ANativeWindow* window,
         int w, int h, int format)
 {
     return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
diff --git a/include/sysutils/FrameworkListener.h b/include/sysutils/FrameworkListener.h
index f1a4b43..18049cd 100644
--- a/include/sysutils/FrameworkListener.h
+++ b/include/sysutils/FrameworkListener.h
@@ -36,6 +36,7 @@
 public:
     FrameworkListener(const char *socketName);
     FrameworkListener(const char *socketName, bool withSeq);
+    FrameworkListener(int sock);
     virtual ~FrameworkListener() {}
 
 protected:
diff --git a/include/sysutils/SocketListener.h b/include/sysutils/SocketListener.h
index c204a0f..bc93b86 100644
--- a/include/sysutils/SocketListener.h
+++ b/include/sysutils/SocketListener.h
@@ -38,6 +38,7 @@
 
     virtual ~SocketListener();
     int startListener();
+    int startListener(int backlog);
     int stopListener();
 
     void sendBroadcast(int code, const char *msg, bool addErrno);
diff --git a/include/utils/Errors.h b/include/utils/Errors.h
index 0b75b19..46173db 100644
--- a/include/utils/Errors.h
+++ b/include/utils/Errors.h
@@ -41,23 +41,23 @@
 #ifdef _WIN32
 # undef NO_ERROR
 #endif
- 
+
 enum {
     OK                = 0,    // Everything's swell.
     NO_ERROR          = 0,    // No errors.
-    
-    UNKNOWN_ERROR       = 0x80000000,
+
+    UNKNOWN_ERROR       = (-2147483647-1), // INT32_MIN value
 
     NO_MEMORY           = -ENOMEM,
     INVALID_OPERATION   = -ENOSYS,
     BAD_VALUE           = -EINVAL,
-    BAD_TYPE            = 0x80000001,
+    BAD_TYPE            = (UNKNOWN_ERROR + 1),
     NAME_NOT_FOUND      = -ENOENT,
     PERMISSION_DENIED   = -EPERM,
     NO_INIT             = -ENODEV,
     ALREADY_EXISTS      = -EEXIST,
     DEAD_OBJECT         = -EPIPE,
-    FAILED_TRANSACTION  = 0x80000002,
+    FAILED_TRANSACTION  = (UNKNOWN_ERROR + 2),
     JPARKS_BROKE_IT     = -EPIPE,
 #if !defined(HAVE_MS_C_RUNTIME)
     BAD_INDEX           = -EOVERFLOW,
@@ -67,12 +67,12 @@
     UNKNOWN_TRANSACTION = -EBADMSG,
 #else    
     BAD_INDEX           = -E2BIG,
-    NOT_ENOUGH_DATA     = 0x80000003,
-    WOULD_BLOCK         = 0x80000004,
-    TIMED_OUT           = 0x80000005,
-    UNKNOWN_TRANSACTION = 0x80000006,
+    NOT_ENOUGH_DATA     = (UNKNOWN_ERROR + 3),
+    WOULD_BLOCK         = (UNKNOWN_ERROR + 4),
+    TIMED_OUT           = (UNKNOWN_ERROR + 5),
+    UNKNOWN_TRANSACTION = (UNKNOWN_ERROR + 6),
 #endif    
-    FDS_NOT_ALLOWED     = 0x80000007,
+    FDS_NOT_ALLOWED     = (UNKNOWN_ERROR + 7),
 };
 
 // Restore define; enumeration is in "android" namespace, so the value defined
diff --git a/include/utils/Functor.h b/include/utils/Functor.h
index e24ded4..09ea614 100644
--- a/include/utils/Functor.h
+++ b/include/utils/Functor.h
@@ -25,7 +25,7 @@
 public:
     Functor() {}
     virtual ~Functor() {}
-    virtual status_t operator ()(int what, void* data) { return NO_ERROR; }
+    virtual status_t operator ()(int /*what*/, void* /*data*/) { return NO_ERROR; }
 };
 
 }; // namespace android
diff --git a/include/utils/LruCache.h b/include/utils/LruCache.h
index 053bfaf..9248ac9 100644
--- a/include/utils/LruCache.h
+++ b/include/utils/LruCache.h
@@ -56,7 +56,7 @@
 
         bool next() {
             mIndex = mCache.mTable->next(mIndex);
-            return mIndex != -1;
+            return (ssize_t)mIndex != -1;
         }
 
         size_t index() const {
@@ -103,9 +103,13 @@
 
 // Implementation is here, because it's fully templated
 template <typename TKey, typename TValue>
-LruCache<TKey, TValue>::LruCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity),
-    mNullValue(NULL), mTable(new BasicHashtable<TKey, Entry>), mYoungest(NULL), mOldest(NULL),
-    mListener(NULL) {
+LruCache<TKey, TValue>::LruCache(uint32_t maxCapacity)
+    : mTable(new BasicHashtable<TKey, Entry>)
+    , mListener(NULL)
+    , mOldest(NULL)
+    , mYoungest(NULL)
+    , mMaxCapacity(maxCapacity)
+    , mNullValue(NULL) {
 };
 
 template<typename K, typename V>
diff --git a/include/utils/Unicode.h b/include/utils/Unicode.h
index c8c87c3..5b98de2 100644
--- a/include/utils/Unicode.h
+++ b/include/utils/Unicode.h
@@ -22,8 +22,11 @@
 
 extern "C" {
 
+// Definitions exist in C++11
+#if defined __cplusplus && __cplusplus < 201103L
 typedef uint32_t char32_t;
 typedef uint16_t char16_t;
+#endif
 
 // Standard string functions on char16_t strings.
 int strcmp16(const char16_t *, const char16_t *);
diff --git a/init/Android.mk b/init/Android.mk
index 1f43ba6..489dc93 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -17,15 +17,20 @@
 	ueventd_parser.c \
 	watchdogd.c
 
+LOCAL_CFLAGS    += -Wno-unused-parameter
+
 ifeq ($(strip $(INIT_BOOTCHART)),true)
 LOCAL_SRC_FILES += bootchart.c
 LOCAL_CFLAGS    += -DBOOTCHART=1
 endif
 
 ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
-LOCAL_CFLAGS += -DALLOW_LOCAL_PROP_OVERRIDE=1
+LOCAL_CFLAGS += -DALLOW_LOCAL_PROP_OVERRIDE=1 -DALLOW_DISABLE_SELINUX=1
 endif
 
+# Enable ueventd logging
+#LOCAL_CFLAGS += -DLOG_UEVENTS=1
+
 LOCAL_MODULE:= init
 
 LOCAL_FORCE_STATIC_EXECUTABLE := true
@@ -42,6 +47,8 @@
 	libmincrypt \
 	libext4_utils_static
 
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+
 include $(BUILD_EXECUTABLE)
 
 # Make a symlink from /sbin/ueventd and /sbin/watchdogd to /init
diff --git a/init/builtins.c b/init/builtins.c
index e2932d5..b32981e 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -33,7 +33,6 @@
 #include <linux/loop.h>
 #include <cutils/partition_utils.h>
 #include <cutils/android_reboot.h>
-#include <sys/system_properties.h>
 #include <fs_mgr.h>
 
 #include <selinux/selinux.h>
@@ -196,6 +195,8 @@
 {
     if (!(svc->flags & SVC_DISABLED)) {
         service_start(svc, NULL);
+    } else {
+        svc->flags |= SVC_DISABLED_START;
     }
 }
 
@@ -238,6 +239,21 @@
     return write_file("/proc/sys/kernel/domainname", args[1]);
 }
 
+int do_enable(int nargs, char **args)
+{
+    struct service *svc;
+    svc = service_find_by_name(args[1]);
+    if (svc) {
+        svc->flags &= ~(SVC_DISABLED | SVC_RC_DISABLED);
+        if (svc->flags & SVC_DISABLED_START) {
+            service_start(svc, NULL);
+        }
+    } else {
+        return -1;
+    }
+    return 0;
+}
+
 int do_exec(int nargs, char **args)
 {
     return -1;
@@ -846,11 +862,24 @@
 }
 
 int do_loglevel(int nargs, char **args) {
-    if (nargs == 2) {
-        klog_set_level(atoi(args[1]));
-        return 0;
+    int log_level;
+    char log_level_str[PROP_VALUE_MAX] = "";
+    if (nargs != 2) {
+        ERROR("loglevel: missing argument\n");
+        return -EINVAL;
     }
-    return -1;
+
+    if (expand_props(log_level_str, args[1], sizeof(log_level_str))) {
+        ERROR("loglevel: cannot expand '%s'\n", args[1]);
+        return -EINVAL;
+    }
+    log_level = atoi(log_level_str);
+    if (log_level < KLOG_ERROR_LEVEL || log_level > KLOG_DEBUG_LEVEL) {
+        ERROR("loglevel: invalid log level'%d'\n", log_level);
+        return -EINVAL;
+    }
+    klog_set_level(log_level);
+    return 0;
 }
 
 int do_load_persist_props(int nargs, char **args) {
@@ -861,6 +890,14 @@
     return -1;
 }
 
+int do_load_all_props(int nargs, char **args) {
+    if (nargs == 1) {
+        load_all_props();
+        return 0;
+    }
+    return -1;
+}
+
 int do_wait(int nargs, char **args)
 {
     if (nargs == 2) {
diff --git a/init/devices.c b/init/devices.c
index f7df453..e27c311 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2007-2014 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.
@@ -15,6 +15,7 @@
  */
 
 #include <errno.h>
+#include <fnmatch.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -37,7 +38,6 @@
 
 #include <private/android_filesystem_config.h>
 #include <sys/time.h>
-#include <asm/page.h>
 #include <sys/wait.h>
 
 #include <cutils/list.h>
@@ -48,6 +48,8 @@
 #include "util.h"
 #include "log.h"
 
+#define UNUSED __attribute__((__unused__))
+
 #define SYSFS_PREFIX    "/sys"
 #define FIRMWARE_DIR1   "/etc/firmware"
 #define FIRMWARE_DIR2   "/vendor/firmware"
@@ -76,6 +78,7 @@
     unsigned int uid;
     unsigned int gid;
     unsigned short prefix;
+    unsigned short wildcard;
 };
 
 struct perm_node {
@@ -96,7 +99,8 @@
 
 int add_dev_perms(const char *name, const char *attr,
                   mode_t perm, unsigned int uid, unsigned int gid,
-                  unsigned short prefix) {
+                  unsigned short prefix,
+                  unsigned short wildcard) {
     struct perm_node *node = calloc(1, sizeof(*node));
     if (!node)
         return -ENOMEM;
@@ -115,6 +119,7 @@
     node->dp.uid = uid;
     node->dp.gid = gid;
     node->dp.prefix = prefix;
+    node->dp.wildcard = wildcard;
 
     if (attr)
         list_add_tail(&sys_perms, &node->plist);
@@ -129,40 +134,62 @@
     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...
-         */
+    /* upaths omit the "/sys" that paths in this list
+     * contain, so we add 4 when comparing...
+     */
     list_for_each(node, &sys_perms) {
         dp = &(node_to_item(node, struct perm_node, plist))->dp;
         if (dp->prefix) {
             if (strncmp(upath, dp->name + 4, strlen(dp->name + 4)))
                 continue;
+        } else if (dp->wildcard) {
+            if (fnmatch(dp->name + 4, upath, FNM_PATHNAME) != 0)
+                continue;
         } else {
             if (strcmp(upath, dp->name + 4))
                 continue;
         }
 
         if ((strlen(upath) + strlen(dp->attr) + 6) > sizeof(buf))
-            return;
+            break;
 
         sprintf(buf,"/sys%s/%s", upath, dp->attr);
         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);
-           }
-        }
+    }
+
+    // Now fixup SELinux file labels
+    int len = snprintf(buf, sizeof(buf), "/sys%s", upath);
+    if ((len < 0) || ((size_t) len >= sizeof(buf))) {
+        // Overflow
+        return;
+    }
+    if (access(buf, F_OK) == 0) {
+        INFO("restorecon_recursive: %s\n", buf);
+        restorecon_recursive(buf);
     }
 }
 
-static mode_t get_device_perm(const char *path, unsigned *uid, unsigned *gid)
+static bool perm_path_matches(const char *path, struct perms_ *dp)
+{
+    if (dp->prefix) {
+        if (strncmp(path, dp->name, strlen(dp->name)) == 0)
+            return true;
+    } else if (dp->wildcard) {
+        if (fnmatch(dp->name, path, FNM_PATHNAME) == 0)
+            return true;
+    } else {
+        if (strcmp(path, dp->name) == 0)
+            return true;
+    }
+
+    return false;
+}
+
+static mode_t get_device_perm(const char *path, const char **links,
+                unsigned *uid, unsigned *gid)
 {
     mode_t perm;
     struct listnode *node;
@@ -173,19 +200,30 @@
      * override ueventd.rc
      */
     list_for_each_reverse(node, &dev_perms) {
+        bool match = false;
+
         perm_node = node_to_item(node, struct perm_node, plist);
         dp = &perm_node->dp;
 
-        if (dp->prefix) {
-            if (strncmp(path, dp->name, strlen(dp->name)))
-                continue;
+        if (perm_path_matches(path, dp)) {
+            match = true;
         } else {
-            if (strcmp(path, dp->name))
-                continue;
+            if (links) {
+                int i;
+                for (i = 0; links[i]; i++) {
+                    if (perm_path_matches(links[i], dp)) {
+                        match = true;
+                        break;
+                    }
+                }
+            }
         }
-        *uid = dp->uid;
-        *gid = dp->gid;
-        return dp->perm;
+
+        if (match) {
+            *uid = dp->uid;
+            *gid = dp->gid;
+            return dp->perm;
+        }
     }
     /* Default if nothing found. */
     *uid = 0;
@@ -194,8 +232,9 @@
 }
 
 static void make_device(const char *path,
-                        const char *upath,
-                        int block, int major, int minor)
+                        const char *upath UNUSED,
+                        int block, int major, int minor,
+                        const char **links)
 {
     unsigned uid;
     unsigned gid;
@@ -203,10 +242,10 @@
     dev_t dev;
     char *secontext = NULL;
 
-    mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
+    mode = get_device_perm(path, links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
 
     if (sehandle) {
-        selabel_lookup(sehandle, &secontext, path, mode);
+        selabel_lookup_best_match(sehandle, &secontext, path, links, mode);
         setfscreatecon(secontext);
     }
 
@@ -297,6 +336,37 @@
     }
 }
 
+/* Given a path that may start with a PCI device, populate the supplied buffer
+ * with the PCI domain/bus number and the peripheral ID and return 0.
+ * If it doesn't start with a PCI device, or there is some error, return -1 */
+static int find_pci_device_prefix(const char *path, char *buf, ssize_t buf_sz)
+{
+    const char *start, *end;
+
+    if (strncmp(path, "/devices/pci", 12))
+        return -1;
+
+    /* Beginning of the prefix is the initial "pci" after "/devices/" */
+    start = path + 9;
+
+    /* End of the prefix is two path '/' later, capturing the domain/bus number
+     * and the peripheral ID. Example: pci0000:00/0000:00:1f.2 */
+    end = strchr(start, '/');
+    if (!end)
+        return -1;
+    end = strchr(end + 1, '/');
+    if (!end)
+        return -1;
+
+    /* Make sure we have enough room for the string plus null terminator */
+    if (end - start + 1 > buf_sz)
+        return -1;
+
+    strncpy(buf, start, end - start);
+    buf[end - start] = '\0';
+    return 0;
+}
+
 #if LOG_UEVENTS
 
 static inline suseconds_t get_usecs(void)
@@ -421,11 +491,12 @@
     return NULL;
 }
 
-static char **parse_platform_block_device(struct uevent *uevent)
+static char **get_block_device_symlinks(struct uevent *uevent)
 {
     const char *device;
     struct platform_node *pdev;
     char *slash;
+    const char *type;
     int width;
     char buf[256];
     char link_path[256];
@@ -437,18 +508,24 @@
     struct stat info;
 
     pdev = find_platform_device(uevent->path);
-    if (!pdev)
+    if (pdev) {
+        device = pdev->name;
+        type = "platform";
+    } else if (!find_pci_device_prefix(uevent->path, buf, sizeof(buf))) {
+        device = buf;
+        type = "pci";
+    } else {
         return NULL;
-    device = pdev->name;
+    }
 
     char **links = malloc(sizeof(char *) * 4);
     if (!links)
         return NULL;
     memset(links, 0, sizeof(char *) * 4);
 
-    INFO("found platform device %s\n", device);
+    INFO("found %s device %s\n", type, device);
 
-    snprintf(link_path, sizeof(link_path), "/dev/block/platform/%s", device);
+    snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device);
 
     if (uevent->partition_name) {
         p = strdup(uevent->partition_name);
@@ -484,7 +561,7 @@
     int i;
 
     if(!strcmp(action, "add")) {
-        make_device(devpath, path, block, major, minor);
+        make_device(devpath, path, block, major, minor, (const char **)links);
         if (links) {
             for (i = 0; links[i]; i++)
                 make_link(devpath, links[i]);
@@ -555,7 +632,7 @@
     make_dir(base, 0755);
 
     if (!strncmp(uevent->path, "/devices/", 9))
-        links = parse_platform_block_device(uevent);
+        links = get_block_device_symlinks(uevent);
 
     handle_device(uevent->action, devpath, uevent->path, 1,
             uevent->major, uevent->minor, links);
@@ -590,6 +667,11 @@
     mkdir_recursive(dir, 0755);
 }
 
+static inline void __attribute__((__deprecated__)) kernel_logger()
+{
+    INFO("kernel logger is deprecated\n");
+}
+
 static void handle_generic_device_event(struct uevent *uevent)
 {
     char *base;
@@ -676,6 +758,7 @@
          make_dir(base, 0755);
      } else if(!strncmp(uevent->subsystem, "misc", 4) &&
                  !strncmp(name, "log_", 4)) {
+         kernel_logger();
          base = "/dev/log/";
          make_dir(base, 0755);
          name += 4;
@@ -692,7 +775,7 @@
 
 static void handle_device_event(struct uevent *uevent)
 {
-    if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change"))
+    if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change") || !strcmp(uevent->action, "online"))
         fixup_sys_perms(uevent->path);
 
     if (!strncmp(uevent->subsystem, "block", 5)) {
diff --git a/init/devices.h b/init/devices.h
index a84fa58..5d0fe88 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -23,6 +23,7 @@
 extern void device_init(void);
 extern int add_dev_perms(const char *name, const char *attr,
                          mode_t perm, unsigned int uid,
-                         unsigned int gid, unsigned short prefix);
+                         unsigned int gid, unsigned short prefix,
+                         unsigned short wildcard);
 int get_device_fd();
 #endif	/* _INIT_DEVICES_H */
diff --git a/init/init.c b/init/init.c
index 00f4558..e4ac1cf 100644
--- a/init/init.c
+++ b/init/init.c
@@ -46,8 +46,6 @@
 #include <private/android_filesystem_config.h>
 #include <termios.h>
 
-#include <sys/system_properties.h>
-
 #include "devices.h"
 #include "init.h"
 #include "log.h"
@@ -164,7 +162,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_RESTART));
+    svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
     svc->time_started = 0;
 
         /* running processes require no additional work -- if
@@ -364,7 +362,7 @@
 {
     /* 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);
+    svc->flags &= ~(SVC_RESTARTING | SVC_DISABLED_START);
 
     if ((how != SVC_DISABLED) && (how != SVC_RESET) && (how != SVC_RESTART)) {
         /* Hrm, an illegal flag.  Default to SVC_DISABLED */
@@ -530,7 +528,8 @@
 
 void execute_one_command(void)
 {
-    int ret;
+    int ret, i;
+    char cmd_str[256] = "";
 
     if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {
         cur_action = action_remove_queue_head();
@@ -547,7 +546,17 @@
         return;
 
     ret = cur_command->func(cur_command->nargs, cur_command->args);
-    INFO("command '%s' r=%d\n", cur_command->args[0], ret);
+    if (klog_get_level() >= KLOG_INFO_LEVEL) {
+        for (i = 0; i < cur_command->nargs; i++) {
+            strlcat(cmd_str, cur_command->args[i], sizeof(cmd_str));
+            if (i < cur_command->nargs - 1) {
+                strlcat(cmd_str, " ", sizeof(cmd_str));
+            }
+        }
+        INFO("command '%s' action=%s status=%d (%s:%d)\n",
+             cmd_str, cur_action ? cur_action->name : "", ret, cur_command->filename,
+             cur_command->line);
+    }
 }
 
 static int wait_for_coldboot_done_action(int nargs, char **args)
@@ -843,24 +852,21 @@
 
 static const struct selinux_opt seopts_prop[] = {
         { SELABEL_OPT_PATH, "/property_contexts" },
+        { SELABEL_OPT_PATH, "/data/security/current/property_contexts" },
         { 0, NULL }
 };
 
 struct selabel_handle* selinux_android_prop_context_handle(void)
 {
-    int i = 0;
-    struct selabel_handle* sehandle = NULL;
-    while ((sehandle == NULL) && seopts_prop[i].value) {
-        sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP, &seopts_prop[i], 1);
-        i++;
-    }
-
+    int policy_index = selinux_android_use_data_policy() ? 1 : 0;
+    struct selabel_handle* sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP,
+                                                   &seopts_prop[policy_index], 1);
     if (!sehandle) {
         ERROR("SELinux:  Could not load property_contexts:  %s\n",
               strerror(errno));
         return NULL;
     }
-    INFO("SELinux: Loaded property contexts from %s\n", seopts_prop[i - 1].value);
+    INFO("SELinux: Loaded property contexts from %s\n", seopts_prop[policy_index].value);
     return sehandle;
 }
 
@@ -873,6 +879,7 @@
 
 static bool selinux_is_disabled(void)
 {
+#ifdef ALLOW_DISABLE_SELINUX
     char tmp[PROP_VALUE_MAX];
 
     if (access("/sys/fs/selinux", F_OK) != 0) {
@@ -886,12 +893,14 @@
         /* SELinux is compiled into the kernel, but we've been told to disable it. */
         return true;
     }
+#endif
 
     return false;
 }
 
 static bool selinux_is_enforcing(void)
 {
+#ifdef ALLOW_DISABLE_SELINUX
     char tmp[PROP_VALUE_MAX];
 
     if (property_get("ro.boot.selinux", tmp) == 0) {
@@ -908,6 +917,7 @@
         ERROR("SELinux: Unknown value of ro.boot.selinux. Got: \"%s\". Assuming enforcing.\n", tmp);
     }
 
+#endif
     return true;
 }
 
@@ -933,12 +943,33 @@
     return 0;
 }
 
-int audit_callback(void *data, security_class_t cls, char *buf, size_t len)
+static int audit_callback(void *data, security_class_t cls __attribute__((unused)), char *buf, size_t len)
 {
     snprintf(buf, len, "property=%s", !data ? "NULL" : (char *)data);
     return 0;
 }
 
+int log_callback(int type, const char *fmt, ...)
+{
+    int level;
+    va_list ap;
+    switch (type) {
+    case SELINUX_WARNING:
+        level = KLOG_WARNING_LEVEL;
+        break;
+    case SELINUX_INFO:
+        level = KLOG_INFO_LEVEL;
+        break;
+    default:
+        level = KLOG_ERROR_LEVEL;
+        break;
+    }
+    va_start(ap, fmt);
+    klog_vwrite(level, fmt, ap);
+    va_end(ap);
+    return 0;
+}
+
 static void selinux_initialize(void)
 {
     if (selinux_is_disabled()) {
@@ -1012,7 +1043,7 @@
     process_kernel_cmdline();
 
     union selinux_callback cb;
-    cb.func_log = klog_write;
+    cb.func_log = log_callback;
     selinux_set_callback(SELINUX_CB_LOG, cb);
 
     cb.func_audit = audit_callback;
@@ -1031,8 +1062,7 @@
     is_charger = !strcmp(bootmode, "charger");
 
     INFO("property init\n");
-    if (!is_charger)
-        property_load_boot_defaults();
+    property_load_boot_defaults();
 
     INFO("reading config file\n");
     init_parse_config_file("/init.rc");
@@ -1047,28 +1077,19 @@
     /* execute all the boot actions to get us started */
     action_for_each_trigger("init", action_add_queue_tail);
 
-    /* skip mounting filesystems in charger mode */
-    if (!is_charger) {
-        action_for_each_trigger("early-fs", action_add_queue_tail);
-        action_for_each_trigger("fs", action_add_queue_tail);
-        action_for_each_trigger("post-fs", action_add_queue_tail);
-        action_for_each_trigger("post-fs-data", action_add_queue_tail);
-    }
-
     /* Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
      * wasn't ready immediately after wait_for_coldboot_done
      */
     queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
-
     queue_builtin_action(property_service_init_action, "property_service_init");
     queue_builtin_action(signal_init_action, "signal_init");
     queue_builtin_action(check_startup_action, "check_startup");
 
+    /* Don't mount filesystems or start core system services if in charger mode. */
     if (is_charger) {
         action_for_each_trigger("charger", action_add_queue_tail);
     } else {
-        action_for_each_trigger("early-boot", action_add_queue_tail);
-        action_for_each_trigger("boot", action_add_queue_tail);
+        action_for_each_trigger("late-init", action_add_queue_tail);
     }
 
         /* run all property triggers based on current state of the properties */
diff --git a/init/init.h b/init/init.h
index 736b75b..a7615a3 100644
--- a/init/init.h
+++ b/init/init.h
@@ -29,10 +29,14 @@
     struct listnode clist;
 
     int (*func)(int nargs, char **args);
+
+    int line;
+    const char *filename;
+
     int nargs;
     char *args[1];
 };
-    
+
 struct action {
         /* node in list of all actions */
     struct listnode alist;
@@ -43,7 +47,7 @@
 
     unsigned hash;
     const char *name;
-    
+
     struct listnode commands;
     struct command *current;
 };
@@ -74,6 +78,7 @@
                                  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 SVC_DISABLED_START 0x200 /* a start was requested but it was disabled at the time */
 
 #define NR_SVC_SUPP_GIDS 12    /* twelve supplementary groups */
 
diff --git a/init/init_parser.c b/init/init_parser.c
index f49e698..6466db2 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -33,9 +33,6 @@
 #include <cutils/iosched_policy.h>
 #include <cutils/list.h>
 
-#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
-#include <sys/_system_properties.h>
-
 static list_declare(service_list);
 static list_declare(action_list);
 static list_declare(action_queue);
@@ -98,6 +95,7 @@
         if (!strcmp(s, "omainname")) return K_domainname;
         break;
     case 'e':
+        if (!strcmp(s, "nable")) return K_enable;
         if (!strcmp(s, "xec")) return K_exec;
         if (!strcmp(s, "xport")) return K_export;
         break;
@@ -119,6 +117,7 @@
     case 'l':
         if (!strcmp(s, "oglevel")) return K_loglevel;
         if (!strcmp(s, "oad_persist_props")) return K_load_persist_props;
+        if (!strcmp(s, "oad_all_props")) return K_load_all_props;
         break;
     case 'm':
         if (!strcmp(s, "kdir")) return K_mkdir;
@@ -582,6 +581,7 @@
     cmd = calloc(1, sizeof(*cmd));
     cmd->func = func;
     cmd->args[0] = name;
+    cmd->nargs = 1;
     list_add_tail(&act->commands, &cmd->clist);
 
     list_add_tail(&action_list, &act->alist);
@@ -759,7 +759,7 @@
         break;
     case K_setenv: { /* name value */
         struct svcenvinfo *ei;
-        if (nargs < 2) {
+        if (nargs < 3) {
             parse_error(state, "setenv option requires name and value arguments\n");
             break;
         }
@@ -868,6 +868,8 @@
     }
     cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
     cmd->func = kw_func(kw);
+    cmd->line = state->line;
+    cmd->filename = state->filename;
     cmd->nargs = nargs;
     memcpy(cmd->args, args, sizeof(char*) * nargs);
     list_add_tail(&act->commands, &cmd->clist);
diff --git a/init/keywords.h b/init/keywords.h
index 97fe50c..2d97e5b 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -6,6 +6,7 @@
 int do_class_stop(int nargs, char **args);
 int do_class_reset(int nargs, char **args);
 int do_domainname(int nargs, char **args);
+int do_enable(int nargs, char **args);
 int do_exec(int nargs, char **args);
 int do_export(int nargs, char **args);
 int do_hostname(int nargs, char **args);
@@ -38,6 +39,7 @@
 int do_chmod(int nargs, char **args);
 int do_loglevel(int nargs, char **args);
 int do_load_persist_props(int nargs, char **args);
+int do_load_all_props(int nargs, char **args);
 int do_wait(int nargs, char **args);
 #define __MAKE_KEYWORD_ENUM__
 #define KEYWORD(symbol, flags, nargs, func) K_##symbol,
@@ -55,6 +57,7 @@
     KEYWORD(critical,    OPTION,  0, 0)
     KEYWORD(disabled,    OPTION,  0, 0)
     KEYWORD(domainname,  COMMAND, 1, do_domainname)
+    KEYWORD(enable,      COMMAND, 1, do_enable)
     KEYWORD(exec,        COMMAND, 1, do_exec)
     KEYWORD(export,      COMMAND, 2, do_export)
     KEYWORD(group,       OPTION,  0, 0)
@@ -99,6 +102,7 @@
     KEYWORD(chmod,       COMMAND, 2, do_chmod)
     KEYWORD(loglevel,    COMMAND, 1, do_loglevel)
     KEYWORD(load_persist_props,    COMMAND, 0, do_load_persist_props)
+    KEYWORD(load_all_props,        COMMAND, 0, do_load_all_props)
     KEYWORD(ioprio,      OPTION,  0, 0)
 #ifdef __MAKE_KEYWORD_ENUM__
     KEYWORD_COUNT,
diff --git a/init/log.h b/init/log.h
index 4aac3df..e9cb65a 100644
--- a/init/log.h
+++ b/init/log.h
@@ -23,6 +23,6 @@
 #define NOTICE(x...)  KLOG_NOTICE("init", x)
 #define INFO(x...)    KLOG_INFO("init", x)
 
-#define LOG_UEVENTS        0  /* log uevent messages if 1. verbose */
+extern int log_callback(int type, const char *fmt, ...);
 
 #endif
diff --git a/init/property_service.c b/init/property_service.c
index ac63377e..d112699 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -38,7 +38,6 @@
 #include <sys/types.h>
 #include <netinet/in.h>
 #include <sys/mman.h>
-#include <sys/atomics.h>
 #include <private/android_filesystem_config.h>
 
 #include <selinux/selinux.h>
@@ -56,63 +55,6 @@
 
 static int property_set_fd = -1;
 
-/* White list of permissions for setting property services. */
-struct {
-    const char *prefix;
-    unsigned int uid;
-    unsigned int gid;
-} property_perms[] = {
-    { "net.rmnet0.",      AID_RADIO,    0 },
-    { "net.gprs.",        AID_RADIO,    0 },
-    { "net.ppp",          AID_RADIO,    0 },
-    { "net.qmi",          AID_RADIO,    0 },
-    { "net.lte",          AID_RADIO,    0 },
-    { "net.cdma",         AID_RADIO,    0 },
-    { "ril.",             AID_RADIO,    0 },
-    { "gsm.",             AID_RADIO,    0 },
-    { "persist.radio",    AID_RADIO,    0 },
-    { "net.dns",          AID_RADIO,    0 },
-    { "sys.usb.config",   AID_RADIO,    0 },
-    { "net.",             AID_SYSTEM,   0 },
-    { "dev.",             AID_SYSTEM,   0 },
-    { "runtime.",         AID_SYSTEM,   0 },
-    { "hw.",              AID_SYSTEM,   0 },
-    { "sys.",             AID_SYSTEM,   0 },
-    { "sys.powerctl",     AID_SHELL,    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 },
-    { "debug.",           AID_SYSTEM,   0 },
-    { "debug.",           AID_SHELL,    0 },
-    { "log.",             AID_SHELL,    0 },
-    { "service.adb.root", AID_SHELL,    0 },
-    { "service.adb.tcp.port", AID_SHELL,    0 },
-    { "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 }
-};
-
-/*
- * White list of UID that are allowed to start/stop services.
- * Currently there are no user apps that require.
- */
-struct {
-    const char *service;
-    unsigned int uid;
-    unsigned int gid;
-} control_perms[] = {
-    { "dumpstate",AID_SHELL, AID_LOG },
-    { "ril-daemon",AID_RADIO, AID_RADIO },
-     {NULL, 0, 0 }
-};
-
 typedef struct {
     size_t size;
     int fd;
@@ -194,34 +136,10 @@
 }
 
 /*
- * Checks permissions for starting/stoping system services.
- * AID_SYSTEM and AID_ROOT are always allowed.
- *
- * Returns 1 if uid allowed, 0 otherwise.
- */
-static int check_control_perms(const char *name, unsigned int uid, unsigned int gid, char *sctx) {
-
-    int i;
-    if (uid == AID_SYSTEM || uid == AID_ROOT)
-      return check_control_mac_perms(name, sctx);
-
-    /* Search the ACL */
-    for (i = 0; control_perms[i].service; i++) {
-        if (strcmp(control_perms[i].service, name) == 0) {
-            if ((uid && control_perms[i].uid == uid) ||
-                (gid && control_perms[i].gid == gid)) {
-                return check_control_mac_perms(name, sctx);
-            }
-        }
-    }
-    return 0;
-}
-
-/*
  * Checks permissions for setting system properties.
  * Returns 1 if uid allowed, 0 otherwise.
  */
-static int check_perms(const char *name, unsigned int uid, unsigned int gid, char *sctx)
+static int check_perms(const char *name, char *sctx)
 {
     int i;
     unsigned int app_id;
@@ -229,26 +147,7 @@
     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) {
-            if ((uid && property_perms[i].uid == uid) ||
-                (gid && property_perms[i].gid == gid)) {
-
-                return check_mac_perms(name, sctx);
-            }
-        }
-    }
-
-    return 0;
+    return check_mac_perms(name, sctx);
 }
 
 int __property_get(const char *name, char *value)
@@ -269,6 +168,7 @@
         return;
     }
     write(fd, value, strlen(value));
+    fsync(fd);
     close(fd);
 
     snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name);
@@ -405,14 +305,14 @@
             // Keep the old close-socket-early behavior when handling
             // ctl.* properties.
             close(s);
-            if (check_control_perms(msg.value, cr.uid, cr.gid, source_ctx)) {
+            if (check_control_mac_perms(msg.value, source_ctx)) {
                 handle_control_message((char*) msg.name + 4, (char*) msg.value);
             } else {
                 ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n",
                         msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);
             }
         } else {
-            if (check_perms(msg.name, cr.uid, cr.gid, source_ctx)) {
+            if (check_perms(msg.name, source_ctx)) {
                 property_set((char*) msg.name, (char*) msg.value);
             } else {
                 ERROR("sys_prop: permission denied uid:%d  name:%s\n",
@@ -439,40 +339,73 @@
     *sz = pa_workspace.size;
 }
 
-static void load_properties(char *data, char *prefix)
-{
-    char *key, *value, *eol, *sol, *tmp;
-    size_t plen;
+static void load_properties_from_file(const char *, const char *);
 
-    if (prefix)
-        plen = strlen(prefix);
+/*
+ * Filter is used to decide which properties to load: NULL loads all keys,
+ * "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match.
+ */
+static void load_properties(char *data, const char *filter)
+{
+    char *key, *value, *eol, *sol, *tmp, *fn;
+    size_t flen = 0;
+
+    if (filter) {
+        flen = strlen(filter);
+    }
+
     sol = data;
-    while((eol = strchr(sol, '\n'))) {
+    while ((eol = strchr(sol, '\n'))) {
         key = sol;
         *eol++ = 0;
         sol = eol;
 
-        value = strchr(key, '=');
-        if(value == 0) continue;
-        *value++ = 0;
+        while (isspace(*key)) key++;
+        if (*key == '#') continue;
 
-        while(isspace(*key)) key++;
-        if(*key == '#') continue;
-        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;
+        while ((tmp > key) && isspace(*tmp)) *tmp-- = 0;
 
-        property_set(key, value);
+        if (!strncmp(key, "import ", 7) && flen == 0) {
+            fn = key + 7;
+            while (isspace(*fn)) fn++;
+
+            key = strchr(fn, ' ');
+            if (key) {
+                *key++ = 0;
+                while (isspace(*key)) key++;
+            }
+
+            load_properties_from_file(fn, key);
+
+        } else {
+            value = strchr(key, '=');
+            if (!value) continue;
+            *value++ = 0;
+
+            tmp = value - 2;
+            while ((tmp > key) && isspace(*tmp)) *tmp-- = 0;
+
+            while (isspace(*value)) value++;
+
+            if (flen > 0) {
+                if (filter[flen - 1] == '*') {
+                    if (strncmp(key, filter, flen - 1)) continue;
+                } else {
+                    if (strcmp(key, filter)) continue;
+                }
+            }
+
+            property_set(key, value);
+        }
     }
 }
 
-static void load_properties_from_file(const char *fn, char *prefix)
+/*
+ * Filter is used to decide which properties to load: NULL loads all keys,
+ * "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match.
+ */
+static void load_properties_from_file(const char *fn, const char *filter)
 {
     char *data;
     unsigned sz;
@@ -480,7 +413,7 @@
     data = read_file(fn, &sz);
 
     if(data != 0) {
-        load_properties(data, prefix);
+        load_properties(data, filter);
         free(data);
     }
 }
@@ -523,7 +456,8 @@
                     || (sb.st_gid != 0)
                     || (sb.st_nlink != 1)) {
                 ERROR("skipping insecure property file %s (uid=%u gid=%u nlink=%d mode=%o)\n",
-                      entry->d_name, sb.st_uid, sb.st_gid, sb.st_nlink, sb.st_mode);
+                      entry->d_name, (unsigned int)sb.st_uid, (unsigned int)sb.st_gid,
+                      sb.st_nlink, sb.st_mode);
                 close(fd);
                 continue;
             }
@@ -586,17 +520,22 @@
     load_persistent_properties();
 }
 
+void load_all_props(void)
+{
+    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();
+}
+
 void start_property_service(void)
 {
     int fd;
 
-    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, NULL);
     if(fd < 0) return;
     fcntl(fd, F_SETFD, FD_CLOEXEC);
diff --git a/init/property_service.h b/init/property_service.h
index 46cbd8f..730495e 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -24,6 +24,7 @@
 extern void property_init(void);
 extern void property_load_boot_defaults(void);
 extern void load_persist_props(void);
+extern void load_all_props(void);
 extern void start_property_service(void);
 void get_property_workspace(int *fd, int *sz);
 extern int __property_get(const char *name, char *value);
diff --git a/init/readme.txt b/init/readme.txt
index 42a09cb..613a9e9 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -178,6 +178,16 @@
 domainname <name>
    Set the domain name.
 
+enable <servicename>
+   Turns a disabled service into an enabled one as if the service did not
+   specify disabled.
+   If the service is supposed to be running, it will be started now.
+   Typically used when the bootloader sets a variable that indicates a specific
+   service should be started when needed. E.g.
+     on property:ro.boot.myfancyhardware=1
+        enable my_fancy_service_for_my_fancy_hardware
+
+
 insmod <path>
    Install the module at <path>
 
diff --git a/init/ueventd.c b/init/ueventd.c
index 3d01836..833e4fd 100644
--- a/init/ueventd.c
+++ b/init/ueventd.c
@@ -21,6 +21,7 @@
 #include <stdio.h>
 #include <ctype.h>
 #include <signal.h>
+#include <selinux/selinux.h>
 
 #include <private/android_filesystem_config.h>
 
@@ -69,6 +70,16 @@
 
     open_devnull_stdio();
     klog_init();
+#if LOG_UEVENTS
+    /* Ensure we're at a logging level that will show the events */
+    if (klog_get_level() < KLOG_INFO_LEVEL) {
+        klog_set_level(KLOG_INFO_LEVEL);
+    }
+#endif
+
+    union selinux_callback cb;
+    cb.func_log = log_callback;
+    selinux_set_callback(SELINUX_CB_LOG, cb);
 
     INFO("starting ueventd\n");
 
@@ -116,6 +127,7 @@
     uid_t uid;
     gid_t gid;
     int prefix = 0;
+    int wildcard = 0;
     char *endptr;
     int ret;
     char *tmp = 0;
@@ -148,9 +160,13 @@
         name = tmp;
     } else {
         int len = strlen(name);
-        if (name[len - 1] == '*') {
+        char *wildcard_chr = strchr(name, '*');
+        if ((name[len - 1] == '*') &&
+            (wildcard_chr == (name + len - 1))) {
             prefix = 1;
             name[len - 1] = '\0';
+        } else if (wildcard_chr) {
+            wildcard = 1;
         }
     }
 
@@ -177,6 +193,6 @@
     }
     gid = ret;
 
-    add_dev_perms(name, attr, perm, uid, gid, prefix);
+    add_dev_perms(name, attr, perm, uid, gid, prefix, wildcard);
     free(tmp);
 }
diff --git a/init/util.c b/init/util.c
index e772342..0f69e1c 100644
--- a/init/util.c
+++ b/init/util.c
@@ -527,10 +527,10 @@
 
 int restorecon(const char* pathname)
 {
-    return selinux_android_restorecon(pathname);
+    return selinux_android_restorecon(pathname, 0);
 }
 
 int restorecon_recursive(const char* pathname)
 {
-    return selinux_android_restorecon_recursive(pathname);
+    return selinux_android_restorecon(pathname, SELINUX_ANDROID_RESTORECON_RECURSE);
 }
diff --git a/libbacktrace/Android.build.mk b/libbacktrace/Android.build.mk
new file mode 100644
index 0000000..2f55645
--- /dev/null
+++ b/libbacktrace/Android.build.mk
@@ -0,0 +1,81 @@
+#
+# Copyright (C) 2014 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 $(CLEAR_VARS)
+
+LOCAL_MODULE := $(module)
+LOCAL_MODULE_TAGS := $(module_tag)
+LOCAL_MULTILIB := $($(module)_multilib)
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+    $(LOCAL_PATH)/Android.mk \
+    $(LOCAL_PATH)/Android.build.mk \
+
+LOCAL_CFLAGS := \
+    $(common_cflags) \
+    $($(module)_cflags) \
+    $($(module)_cflags_$(build_type)) \
+
+LOCAL_CONLYFLAGS += \
+    $(common_conlyflags) \
+    $($(module)_conlyflags) \
+    $($(module)_conlyflags_$(build_type)) \
+
+LOCAL_CPPFLAGS += \
+    $(common_cppflags) \
+    $($(module)_cppflags) \
+    $($(module)_cppflags_$(build_type)) \
+
+LOCAL_C_INCLUDES := \
+    $(common_c_includes) \
+    $($(module)_c_includes) \
+    $($(module)_c_includes_$(build_type)) \
+
+LOCAL_SRC_FILES := \
+    $($(module)_src_files) \
+    $($(module)_src_files_$(build_type)) \
+
+LOCAL_STATIC_LIBRARIES := \
+    $($(module)_static_libraries) \
+    $($(module)_static_libraries_$(build_type)) \
+
+LOCAL_SHARED_LIBRARIES := \
+    $($(module)_shared_libraries) \
+    $($(module)_shared_libraries_$(build_type)) \
+
+LOCAL_LDLIBS := \
+    $($(module)_ldlibs) \
+    $($(module)_ldlibs_$(build_type)) \
+
+ifeq ($(build_type),target)
+  ifneq ($($(module)_libc++),)
+    include external/libcxx/libcxx.mk
+  else
+    include external/stlport/libstlport.mk
+  endif
+
+  include $(BUILD_$(build_target))
+endif
+
+ifeq ($(build_type),host)
+  # Only build if host builds are supported.
+  ifeq ($(build_host),true)
+    ifneq ($($(module)_libc++),)
+      include external/libcxx/libcxx.mk
+    endif
+    include $(BUILD_HOST_$(build_target))
+  endif
+endif
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
old mode 100644
new mode 100755
index 80cd861..c321369
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -1,14 +1,23 @@
-LOCAL_PATH:= $(call my-dir)
+#
+# Copyright (C) 2014 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.
+#
 
-common_src := \
-	BacktraceImpl.cpp \
-	BacktraceMap.cpp \
-	BacktraceThread.cpp \
-	thread_utils.c \
+LOCAL_PATH:= $(call my-dir)
 
 common_cflags := \
 	-Wall \
-	-Wno-unused-parameter \
 	-Werror \
 
 common_conlyflags := \
@@ -17,274 +26,185 @@
 common_cppflags := \
 	-std=gnu++11 \
 
-common_shared_libs := \
+build_host := false
+ifeq ($(HOST_OS),linux)
+ifeq ($(HOST_ARCH),$(filter $(HOST_ARCH),x86 x86_64))
+build_host := true
+endif
+endif
+
+#-------------------------------------------------------------------------
+# The libbacktrace library.
+#-------------------------------------------------------------------------
+libbacktrace_src_files := \
+	BacktraceImpl.cpp \
+	BacktraceMap.cpp \
+	BacktraceThread.cpp \
+	thread_utils.c \
+
+libbacktrace_shared_libraries_target := \
 	libcutils \
 	libgccdemangle \
-	liblog \
 
-# To enable using libunwind on each arch, add it to this list.
-libunwind_architectures :=
-
-ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),$(libunwind_architectures)))
-
-#----------------------------------------------------------------------------
-# The native libbacktrace library with libunwind.
-#----------------------------------------------------------------------------
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	$(common_src) \
+libbacktrace_src_files += \
 	UnwindCurrent.cpp \
 	UnwindMap.cpp \
 	UnwindPtrace.cpp \
 
-LOCAL_CFLAGS := \
-	$(common_cflags) \
-
-LOCAL_CONLYFLAGS += \
-	$(common_conlyflags) \
-
-LOCAL_CPPFLAGS += \
-	$(common_cppflags) \
-
-LOCAL_MODULE := libbacktrace
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_C_INCLUDES := \
-	$(common_c_includes) \
+libbacktrace_c_includes := \
 	external/libunwind/include \
 
-LOCAL_SHARED_LIBRARIES := \
-	$(common_shared_libs) \
+libbacktrace_shared_libraries := \
 	libunwind \
 	libunwind-ptrace \
 
-LOCAL_ADDITIONAL_DEPENDENCIES := \
-	$(LOCAL_PATH)/Android.mk
-
-include external/stlport/libstlport.mk
-
-include $(BUILD_SHARED_LIBRARY)
-
-else
-
-#----------------------------------------------------------------------------
-# The native libbacktrace library with libcorkscrew.
-#----------------------------------------------------------------------------
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	$(common_src) \
-	Corkscrew.cpp \
-
-LOCAL_CFLAGS := \
-	$(common_cflags) \
-
-LOCAL_CONLYFLAGS += \
-	$(common_conlyflags) \
-
-LOCAL_CPPFLAGS += \
-	$(common_cppflags) \
-
-LOCAL_MODULE := libbacktrace
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_C_INCLUDES := \
-	$(common_c_includes) \
-	system/core/libcorkscrew \
-
-LOCAL_SHARED_LIBRARIES := \
-	$(common_shared_libs) \
-	libcorkscrew \
-	libdl \
-
-LOCAL_ADDITIONAL_DEPENDENCIES := \
-	$(LOCAL_PATH)/Android.mk
-
-include external/stlport/libstlport.mk
-
-include $(BUILD_SHARED_LIBRARY)
-
-endif
-
-#----------------------------------------------------------------------------
-# libbacktrace test library, all optimizations turned off
-#----------------------------------------------------------------------------
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libbacktrace_test
-LOCAL_MODULE_FLAGS := debug
-
-LOCAL_SRC_FILES := \
-	backtrace_testlib.c
-
-LOCAL_CFLAGS += \
-	-std=gnu99 \
-	-O0 \
-
-LOCAL_ADDITIONAL_DEPENDENCIES := \
-	$(LOCAL_PATH)/Android.mk
-
-include $(BUILD_SHARED_LIBRARY)
-
-#----------------------------------------------------------------------------
-# libbacktrace test executable
-#----------------------------------------------------------------------------
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := backtrace_test
-LOCAL_MODULE_FLAGS := debug
-
-LOCAL_SRC_FILES := \
-	backtrace_test.cpp \
-	thread_utils.c \
-
-LOCAL_CFLAGS += \
-	$(common_cflags) \
-	-fno-builtin \
-	-fstack-protector-all \
-	-O0 \
-	-g \
-	-DGTEST_OS_LINUX_ANDROID \
-	-DGTEST_HAS_STD_STRING \
-
-ifeq ($(TARGET_ARCH),arm64)
-  $(info TODO: $(LOCAL_PATH)/Android.mk -fstack-protector not yet available for the AArch64 toolchain)
-  LOCAL_CFLAGS += -fno-stack-protector
-endif # arm64
-
-LOCAL_CONLYFLAGS += \
-	$(common_conlyflags) \
-
-LOCAL_CPPFLAGS += \
-	$(common_cppflags) \
-
-LOCAL_SHARED_LIBRARIES += \
-	libcutils \
-	libbacktrace_test \
-	libbacktrace \
-
-LOCAL_LDLIBS := \
-	-lpthread \
-
-LOCAL_ADDITIONAL_DEPENDENCIES := \
-	$(LOCAL_PATH)/Android.mk
-
-include $(BUILD_NATIVE_TEST)
-
-#----------------------------------------------------------------------------
-# Only x86 host versions of libbacktrace supported.
-#----------------------------------------------------------------------------
-ifeq ($(HOST_ARCH),x86)
-
-#----------------------------------------------------------------------------
-# The host libbacktrace library using libcorkscrew
-#----------------------------------------------------------------------------
-include $(CLEAR_VARS)
-
-
-LOCAL_CFLAGS += \
-	$(common_cflags) \
-
-LOCAL_CONLYFLAGS += \
-	$(common_conlyflags) \
-
-LOCAL_C_INCLUDES := \
-	$(common_c_includes) \
-
-LOCAL_SHARED_LIBRARIES := \
-	libgccdemangle \
+libbacktrace_shared_libraries_host := \
 	liblog \
 
-LOCAL_MODULE := libbacktrace
-LOCAL_MODULE_TAGS := optional
+libbacktrace_static_libraries_host := \
+	libcutils \
 
-LOCAL_ADDITIONAL_DEPENDENCIES := \
-	$(LOCAL_PATH)/Android.mk
+module := libbacktrace
+module_tag := optional
+build_type := target
+build_target := SHARED_LIBRARY
+include $(LOCAL_PATH)/Android.build.mk
+build_type := host
+include $(LOCAL_PATH)/Android.build.mk
 
-ifeq ($(HOST_OS),linux)
-LOCAL_SRC_FILES += \
-	$(common_src) \
-	Corkscrew.cpp \
-
-LOCAL_C_INCLUDES += \
-	system/core/libcorkscrew \
-
-LOCAL_SHARED_LIBRARIES := \
-	libcorkscrew \
-
-LOCAL_CPPFLAGS += \
-	$(common_cppflags) \
-
-LOCAL_LDLIBS += \
-	-ldl \
-	-lrt \
-
-else
-LOCAL_SRC_FILES += \
+# Don't build for unbundled branches
+ifeq (,$(TARGET_BUILD_APPS))
+#-------------------------------------------------------------------------
+# The libbacktrace library (libc++)
+#-------------------------------------------------------------------------
+libbacktrace_libc++_src_files := \
+	BacktraceImpl.cpp \
 	BacktraceMap.cpp \
-
-endif
-
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-#----------------------------------------------------------------------------
-# The host test is only supported on linux.
-#----------------------------------------------------------------------------
-ifeq ($(HOST_OS),linux)
-
-#----------------------------------------------------------------------------
-# libbacktrace host test library, all optimizations turned off
-#----------------------------------------------------------------------------
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libbacktrace_test
-LOCAL_MODULE_FLAGS := debug
-
-LOCAL_SRC_FILES := \
-	backtrace_testlib.c
-
-LOCAL_CFLAGS += \
-	-std=gnu99 \
-	-O0 \
-
-LOCAL_ADDITIONAL_DEPENDENCIES := \
-	$(LOCAL_PATH)/Android.mk
-
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-#----------------------------------------------------------------------------
-# libbacktrace host test executable
-#----------------------------------------------------------------------------
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := backtrace_test
-LOCAL_MODULE_FLAGS := debug
-
-LOCAL_SRC_FILES := \
-	backtrace_test.cpp \
+	BacktraceThread.cpp \
 	thread_utils.c \
 
-LOCAL_CFLAGS += \
-	$(common_cflags) \
+libbacktrace_libc++_shared_libraries_target := \
+	libcutils \
+	libgccdemangle \
+
+libbacktrace_libc++_src_files += \
+	UnwindCurrent.cpp \
+	UnwindMap.cpp \
+	UnwindPtrace.cpp \
+
+libbacktrace_libc++_c_includes := \
+	external/libunwind/include \
+
+libbacktrace_libc++_shared_libraries := \
+	libunwind \
+	libunwind-ptrace \
+
+libbacktrace_libc++_shared_libraries_host := \
+	liblog \
+
+libbacktrace_libc++_static_libraries_host := \
+	libcutils \
+
+libbacktrace_libc++_libc++ := true
+
+module := libbacktrace_libc++
+module_tag := optional
+build_type := target
+build_target := SHARED_LIBRARY
+include $(LOCAL_PATH)/Android.build.mk
+build_type := host
+libbacktrace_libc++_multilib := both
+include $(LOCAL_PATH)/Android.build.mk
+libbacktrace_libc++_multilib :=
+endif
+
+#-------------------------------------------------------------------------
+# The libbacktrace_test library needed by backtrace_test.
+#-------------------------------------------------------------------------
+libbacktrace_test_cflags := \
+	-O0 \
+
+libbacktrace_test_src_files := \
+	backtrace_testlib.c \
+
+module := libbacktrace_test
+module_tag := debug
+build_type := target
+build_target := SHARED_LIBRARY
+include $(LOCAL_PATH)/Android.build.mk
+build_type := host
+include $(LOCAL_PATH)/Android.build.mk
+
+#-------------------------------------------------------------------------
+# The backtrace_test executable.
+#-------------------------------------------------------------------------
+backtrace_test_cflags := \
 	-fno-builtin \
-	-fstack-protector-all \
 	-O0 \
 	-g \
-	-DGTEST_HAS_STD_STRING \
 
-LOCAL_SHARED_LIBRARIES := \
+backtrace_test_cflags_target := \
+	-DENABLE_PSS_TESTS \
+
+backtrace_test_src_files := \
+	backtrace_test.cpp \
+	GetPss.cpp \
+	thread_utils.c \
+
+backtrace_test_ldlibs_host := \
+	-lpthread \
+	-lrt \
+
+backtrace_test_shared_libraries := \
 	libbacktrace_test \
 	libbacktrace \
 
-LOCAL_LDLIBS := \
-	-lpthread \
+backtrace_test_shared_libraries_target := \
+	libcutils \
 
-LOCAL_ADDITIONAL_DEPENDENCIES := \
-	$(LOCAL_PATH)/Android.mk
+backtrace_test_static_libraries_host := \
+	libcutils \
 
-include $(BUILD_HOST_NATIVE_TEST)
+module := backtrace_test
+module_tag := debug
+build_type := target
+build_target := NATIVE_TEST
+include $(LOCAL_PATH)/Android.build.mk
+build_type := host
+include $(LOCAL_PATH)/Android.build.mk
 
-endif # HOST_OS == linux
+#----------------------------------------------------------------------------
+# Special truncated libbacktrace library for mac.
+#----------------------------------------------------------------------------
+ifeq ($(HOST_OS),darwin)
 
-endif # HOST_ARCH == x86
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libbacktrace
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+	BacktraceMap.cpp \
+
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+# Don't build for unbundled branches
+ifeq (,$(TARGET_BUILD_APPS))
+#-------------------------------------------------------------------------
+# The libbacktrace library (libc++)
+#-------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libbacktrace_libc++
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+	BacktraceMap.cpp \
+
+LOCAL_MULTILIB := both
+
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+endif # TARGET_BUILD_APPS
+
+endif # HOST_OS-darwin
diff --git a/libbacktrace/BacktraceImpl.cpp b/libbacktrace/BacktraceImpl.cpp
index 39296b4..405b042 100644
--- a/libbacktrace/BacktraceImpl.cpp
+++ b/libbacktrace/BacktraceImpl.cpp
@@ -19,17 +19,16 @@
 #include <string.h>
 #include <sys/ptrace.h>
 #include <sys/types.h>
+#include <ucontext.h>
 #include <unistd.h>
 
-#define __STDC_FORMAT_MACROS
-#include <inttypes.h>
-
 #include <string>
 
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 
 #include "BacktraceImpl.h"
+#include "BacktraceLog.h"
 #include "thread_utils.h"
 
 //-------------------------------------------------------------------------
@@ -57,8 +56,8 @@
   }
 }
 
-bool Backtrace::Unwind(size_t num_ignore_frames) {
-  return impl_->Unwind(num_ignore_frames);
+bool Backtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
+  return impl_->Unwind(num_ignore_frames, ucontext);
 }
 
 extern "C" char* __cxa_demangle(const char* mangled, char* buf, size_t* len,
@@ -82,10 +81,10 @@
   return func_name;
 }
 
-bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value) {
-  if (ptr & 3) {
+bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, word_t* out_value) {
+  if (ptr & (sizeof(word_t)-1)) {
     BACK_LOGW("invalid pointer %p", (void*)ptr);
-    *out_value = (uint32_t)-1;
+    *out_value = (word_t)-1;
     return false;
   }
   return true;
@@ -143,18 +142,18 @@
 BacktraceCurrent::~BacktraceCurrent() {
 }
 
-bool BacktraceCurrent::ReadWord(uintptr_t ptr, uint32_t* out_value) {
+bool BacktraceCurrent::ReadWord(uintptr_t ptr, word_t* out_value) {
   if (!VerifyReadWordArgs(ptr, out_value)) {
     return false;
   }
 
   const backtrace_map_t* map = FindMap(ptr);
   if (map && map->flags & PROT_READ) {
-    *out_value = *reinterpret_cast<uint32_t*>(ptr);
+    *out_value = *reinterpret_cast<word_t*>(ptr);
     return true;
   } else {
     BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr));
-    *out_value = static_cast<uint32_t>(-1);
+    *out_value = static_cast<word_t>(-1);
     return false;
   }
 }
@@ -171,7 +170,7 @@
 BacktracePtrace::~BacktracePtrace() {
 }
 
-bool BacktracePtrace::ReadWord(uintptr_t ptr, uint32_t* out_value) {
+bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) {
   if (!VerifyReadWordArgs(ptr, out_value)) {
     return false;
   }
@@ -184,7 +183,7 @@
   // To disambiguate -1 from a valid result, we clear errno beforehand.
   errno = 0;
   *out_value = ptrace(PTRACE_PEEKTEXT, Tid(), reinterpret_cast<void*>(ptr), NULL);
-  if (*out_value == static_cast<uint32_t>(-1) && errno) {
+  if (*out_value == static_cast<word_t>(-1) && errno) {
     BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s",
               reinterpret_cast<void*>(ptr), Tid(), strerror(errno));
     return false;
diff --git a/libbacktrace/BacktraceImpl.h b/libbacktrace/BacktraceImpl.h
old mode 100644
new mode 100755
index af014d5..d34ad05
--- a/libbacktrace/BacktraceImpl.h
+++ b/libbacktrace/BacktraceImpl.h
@@ -21,17 +21,12 @@
 #include <backtrace/BacktraceMap.h>
 
 #include <sys/types.h>
-#include <log/log.h>
-
-// Macro to log the function name along with the warning message.
-#define BACK_LOGW(format, ...) \
-  ALOGW("%s: " format, __PRETTY_FUNCTION__, ##__VA_ARGS__)
 
 class BacktraceImpl {
 public:
   virtual ~BacktraceImpl() { }
 
-  virtual bool Unwind(size_t num_ignore_frames) = 0;
+  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) = 0;
 
   // The name returned is not demangled, Backtrace::GetFunctionName()
   // takes care of demangling the name.
@@ -61,7 +56,7 @@
   BacktraceCurrent(BacktraceImpl* impl, BacktraceMap* map);
   virtual ~BacktraceCurrent();
 
-  bool ReadWord(uintptr_t ptr, uint32_t* out_value);
+  bool ReadWord(uintptr_t ptr, word_t* out_value);
 };
 
 class BacktracePtrace : public Backtrace {
@@ -69,7 +64,7 @@
   BacktracePtrace(BacktraceImpl* impl, pid_t pid, pid_t tid, BacktraceMap* map);
   virtual ~BacktracePtrace();
 
-  bool ReadWord(uintptr_t ptr, uint32_t* out_value);
+  bool ReadWord(uintptr_t ptr, word_t* out_value);
 };
 
 Backtrace* CreateCurrentObj(BacktraceMap* map);
diff --git a/libbacktrace/BacktraceLog.h b/libbacktrace/BacktraceLog.h
new file mode 100755
index 0000000..1632ec2
--- /dev/null
+++ b/libbacktrace/BacktraceLog.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 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 _LIBBACKTRACE_BACKTRACE_LOG_H
+#define _LIBBACKTRACE_BACKTRACE_LOG_H
+
+#define LOG_TAG "libbacktrace"
+
+#include <log/log.h>
+
+// Macro to log the function name along with the warning message.
+#define BACK_LOGW(format, ...) \
+  ALOGW("%s: " format, __PRETTY_FUNCTION__, ##__VA_ARGS__)
+
+#endif // _LIBBACKTRACE_BACKTRACE_LOG_H
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index 6320800..0056f4b 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -93,7 +93,8 @@
   }
 
   ALOGV("Parsed map: start=%p, end=%p, flags=%x, name=%s",
-        map->start, map->end, map->flags, map->name.c_str());
+        reinterpret_cast<void*>(map->start), reinterpret_cast<void*>(map->end),
+        map->flags, map->name.c_str());
   return true;
 }
 
@@ -107,11 +108,11 @@
 
 #if defined(__APPLE__)
   // cmd is guaranteed to always be big enough to hold this string.
-  sprintf(cmd, "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid_);
+  snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid_);
   FILE* fp = popen(cmd, "r");
 #else
   // path is guaranteed to always be big enough to hold this string.
-  sprintf(path, "/proc/%d/maps", pid_);
+  snprintf(path, sizeof(path), "/proc/%d/maps", pid_);
   FILE* fp = fopen(path, "r");
 #endif
   if (fp == NULL) {
diff --git a/libbacktrace/BacktraceThread.cpp b/libbacktrace/BacktraceThread.cpp
index 5ffe516..b47cd2a 100644
--- a/libbacktrace/BacktraceThread.cpp
+++ b/libbacktrace/BacktraceThread.cpp
@@ -16,200 +16,195 @@
 
 #include <errno.h>
 #include <inttypes.h>
+#include <limits.h>
+#include <linux/futex.h>
 #include <pthread.h>
 #include <signal.h>
 #include <string.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
 #include <sys/types.h>
+#include <ucontext.h>
 
 #include <cutils/atomic.h>
 
+#include "BacktraceLog.h"
 #include "BacktraceThread.h"
 #include "thread_utils.h"
 
+static inline int futex(volatile int* uaddr, int op, int val, const struct timespec* ts, volatile int* uaddr2, int val3) {
+  return syscall(__NR_futex, uaddr, op, val, ts, uaddr2, val3);
+}
+
 //-------------------------------------------------------------------------
 // ThreadEntry implementation.
 //-------------------------------------------------------------------------
-static ThreadEntry* g_list = NULL;
-static pthread_mutex_t g_entry_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER;
+ThreadEntry* ThreadEntry::list_ = NULL;
+pthread_mutex_t ThreadEntry::list_mutex_ = PTHREAD_MUTEX_INITIALIZER;
 
-ThreadEntry::ThreadEntry(
-    BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames)
-    : thread_intf(intf), pid(pid), tid(tid), next(NULL), prev(NULL),
-      state(STATE_WAITING), num_ignore_frames(num_ignore_frames) {
+// Assumes that ThreadEntry::list_mutex_ has already been locked before
+// creating a ThreadEntry object.
+ThreadEntry::ThreadEntry(pid_t pid, pid_t tid)
+    : pid_(pid), tid_(tid), futex_(0), ref_count_(1), mutex_(PTHREAD_MUTEX_INITIALIZER), next_(ThreadEntry::list_), prev_(NULL) {
+  // Add ourselves to the list.
+  if (ThreadEntry::list_) {
+    ThreadEntry::list_->prev_ = this;
+  }
+  ThreadEntry::list_ = this;
 }
 
-ThreadEntry::~ThreadEntry() {
-  pthread_mutex_lock(&g_entry_mutex);
-  if (g_list == this) {
-    g_list = next;
+ThreadEntry* ThreadEntry::Get(pid_t pid, pid_t tid, bool create) {
+  pthread_mutex_lock(&ThreadEntry::list_mutex_);
+  ThreadEntry* entry = list_;
+  while (entry != NULL) {
+    if (entry->Match(pid, tid)) {
+      break;
+    }
+    entry = entry->next_;
+  }
+
+  if (!entry) {
+    if (create) {
+      entry = new ThreadEntry(pid, tid);
+    }
   } else {
-    if (next) {
-      next->prev = prev;
-    }
-    prev->next = next;
+    entry->ref_count_++;
   }
-  pthread_mutex_unlock(&g_entry_mutex);
-
-  next = NULL;
-  prev = NULL;
-}
-
-ThreadEntry* ThreadEntry::AddThreadToUnwind(
-    BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames) {
-  ThreadEntry* entry = new ThreadEntry(intf, pid, tid, num_ignore_frames);
-
-  pthread_mutex_lock(&g_entry_mutex);
-  ThreadEntry* cur_entry = g_list;
-  while (cur_entry != NULL) {
-    if (cur_entry->Match(pid, tid)) {
-      // There is already an entry for this pid/tid, this is bad.
-      BACK_LOGW("Entry for pid %d tid %d already exists.", pid, tid);
-
-      pthread_mutex_unlock(&g_entry_mutex);
-      return NULL;
-    }
-    cur_entry = cur_entry->next;
-  }
-
-  // Add the entry to the list.
-  entry->next = g_list;
-  if (g_list) {
-    g_list->prev = entry;
-  }
-  g_list = entry;
-  pthread_mutex_unlock(&g_entry_mutex);
+  pthread_mutex_unlock(&ThreadEntry::list_mutex_);
 
   return entry;
 }
 
+void ThreadEntry::Remove(ThreadEntry* entry) {
+  pthread_mutex_unlock(&entry->mutex_);
+
+  pthread_mutex_lock(&ThreadEntry::list_mutex_);
+  if (--entry->ref_count_ == 0) {
+    delete entry;
+  }
+  pthread_mutex_unlock(&ThreadEntry::list_mutex_);
+}
+
+// Assumes that ThreadEntry::list_mutex_ has already been locked before
+// deleting a ThreadEntry object.
+ThreadEntry::~ThreadEntry() {
+  if (list_ == this) {
+    list_ = next_;
+  } else {
+    if (next_) {
+      next_->prev_ = prev_;
+    }
+    prev_->next_ = next_;
+  }
+
+  next_ = NULL;
+  prev_ = NULL;
+}
+
+void ThreadEntry::Wait(int value) {
+  timespec ts;
+  ts.tv_sec = 10;
+  ts.tv_nsec = 0;
+  errno = 0;
+  futex(&futex_, FUTEX_WAIT, value, &ts, NULL, 0);
+  if (errno != 0 && errno != EWOULDBLOCK) {
+    BACK_LOGW("futex wait failed, futex = %d: %s", futex_, strerror(errno));
+  }
+}
+
+void ThreadEntry::Wake() {
+  futex_++;
+  futex(&futex_, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
+}
+
+void ThreadEntry::CopyUcontextFromSigcontext(void* sigcontext) {
+  ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(sigcontext);
+  // The only thing the unwinder cares about is the mcontext data.
+  memcpy(&ucontext_.uc_mcontext, &ucontext->uc_mcontext, sizeof(ucontext->uc_mcontext));
+}
+
 //-------------------------------------------------------------------------
 // BacktraceThread functions.
 //-------------------------------------------------------------------------
-static void SignalHandler(int n __attribute__((unused)), siginfo_t* siginfo,
-                          void* sigcontext) {
-  if (pthread_mutex_lock(&g_entry_mutex) == 0) {
-    pid_t pid = getpid();
-    pid_t tid = gettid();
-    ThreadEntry* cur_entry = g_list;
-    while (cur_entry) {
-      if (cur_entry->Match(pid, tid)) {
-        break;
-      }
-      cur_entry = cur_entry->next;
-    }
-    pthread_mutex_unlock(&g_entry_mutex);
-    if (!cur_entry) {
-      BACK_LOGW("Unable to find pid %d tid %d information", pid, tid);
-      return;
-    }
+static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER;
 
-    if (android_atomic_acquire_cas(STATE_WAITING, STATE_DUMPING, &cur_entry->state) == 0) {
-      cur_entry->thread_intf->ThreadUnwind(siginfo, sigcontext,
-                                           cur_entry->num_ignore_frames);
-    }
-    android_atomic_release_store(STATE_DONE, &cur_entry->state);
+static void SignalHandler(int, siginfo_t*, void* sigcontext) {
+  ThreadEntry* entry = ThreadEntry::Get(getpid(), gettid(), false);
+  if (!entry) {
+    BACK_LOGW("Unable to find pid %d tid %d information", getpid(), gettid());
+    return;
   }
+
+  entry->CopyUcontextFromSigcontext(sigcontext);
+
+  // Indicate the ucontext is now valid.
+  entry->Wake();
+
+  // Pause the thread until the unwind is complete. This avoids having
+  // the thread run ahead causing problems.
+  entry->Wait(1);
+
+  ThreadEntry::Remove(entry);
 }
 
-BacktraceThread::BacktraceThread(
-    BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid,
-    BacktraceMap* map)
-    : BacktraceCurrent(impl, map), thread_intf_(thread_intf) {
+BacktraceThread::BacktraceThread(BacktraceImpl* impl, pid_t tid, BacktraceMap* map)
+    : BacktraceCurrent(impl, map) {
   tid_ = tid;
 }
 
 BacktraceThread::~BacktraceThread() {
 }
 
-void BacktraceThread::FinishUnwind() {
-  for (std::vector<backtrace_frame_data_t>::iterator it = frames_.begin();
-       it != frames_.end(); ++it) {
-    it->map = FindMap(it->pc);
-
-    it->func_offset = 0;
-    it->func_name = GetFunctionName(it->pc, &it->func_offset);
-  }
-}
-
-bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) {
-  entry->state = STATE_WAITING;
-
-  if (tgkill(Pid(), Tid(), SIGURG) != 0) {
-    BACK_LOGW("tgkill failed %s", strerror(errno));
-    return false;
-  }
-
-  // Allow up to ten seconds for the dump to start.
-  int wait_millis = 10000;
-  int32_t state;
-  while (true) {
-    state = android_atomic_acquire_load(&entry->state);
-    if (state != STATE_WAITING) {
-      break;
-    }
-    if (wait_millis--) {
-      usleep(1000);
-    } else {
-      break;
-    }
-  }
-
-  bool cancelled = false;
-  if (state == STATE_WAITING) {
-    if (android_atomic_acquire_cas(state, STATE_CANCEL, &entry->state) == 0) {
-      BACK_LOGW("Cancelled dump of thread %d", entry->tid);
-      state = STATE_CANCEL;
-      cancelled = true;
-    } else {
-      state = android_atomic_acquire_load(&entry->state);
-    }
-  }
-
-  // Wait for at most ten seconds for the cancel or dump to finish.
-  wait_millis = 10000;
-  while (android_atomic_acquire_load(&entry->state) != STATE_DONE) {
-    if (wait_millis--) {
-      usleep(1000);
-    } else {
-      BACK_LOGW("Didn't finish thread unwind in 60 seconds.");
-      break;
-    }
-  }
-  return !cancelled;
-}
-
-bool BacktraceThread::Unwind(size_t num_ignore_frames) {
-  ThreadEntry* entry = ThreadEntry::AddThreadToUnwind(
-      thread_intf_, Pid(), Tid(), num_ignore_frames);
-  if (!entry) {
-    return false;
+bool BacktraceThread::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
+  if (ucontext) {
+    // Unwind using an already existing ucontext.
+    return impl_->Unwind(num_ignore_frames, ucontext);
   }
 
   // Prevent multiple threads trying to set the trigger action on different
   // threads at the same time.
-  bool retval = false;
-  if (pthread_mutex_lock(&g_sigaction_mutex) == 0) {
-    struct sigaction act, oldact;
-    memset(&act, 0, sizeof(act));
-    act.sa_sigaction = SignalHandler;
-    act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
-    sigemptyset(&act.sa_mask);
-    if (sigaction(SIGURG, &act, &oldact) == 0) {
-      retval = TriggerUnwindOnThread(entry);
-      sigaction(SIGURG, &oldact, NULL);
-    } else {
-      BACK_LOGW("sigaction failed %s", strerror(errno));
-    }
+  if (pthread_mutex_lock(&g_sigaction_mutex) < 0) {
+    BACK_LOGW("sigaction failed: %s", strerror(errno));
+    return false;
+  }
+
+  ThreadEntry* entry = ThreadEntry::Get(Pid(), Tid());
+  entry->Lock();
+
+  struct sigaction act, oldact;
+  memset(&act, 0, sizeof(act));
+  act.sa_sigaction = SignalHandler;
+  act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
+  sigemptyset(&act.sa_mask);
+  if (sigaction(THREAD_SIGNAL, &act, &oldact) != 0) {
+    BACK_LOGW("sigaction failed %s", strerror(errno));
+    entry->Unlock();
+    ThreadEntry::Remove(entry);
     pthread_mutex_unlock(&g_sigaction_mutex);
-  } else {
-    BACK_LOGW("unable to acquire sigaction mutex.");
+    return false;
   }
 
-  if (retval) {
-    FinishUnwind();
+  if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) {
+    BACK_LOGW("tgkill %d failed: %s", Tid(), strerror(errno));
+    sigaction(THREAD_SIGNAL, &oldact, NULL);
+    entry->Unlock();
+    ThreadEntry::Remove(entry);
+    pthread_mutex_unlock(&g_sigaction_mutex);
+    return false;
   }
-  delete entry;
 
-  return retval;
+  // Wait for the thread to get the ucontext.
+  entry->Wait(0);
+
+  // After the thread has received the signal, allow other unwinders to
+  // continue.
+  sigaction(THREAD_SIGNAL, &oldact, NULL);
+  pthread_mutex_unlock(&g_sigaction_mutex);
+
+  bool unwind_done = impl_->Unwind(num_ignore_frames, entry->GetUcontext());
+
+  // Tell the signal handler to exit and release the entry.
+  entry->Wake();
+
+  return unwind_done;
 }
diff --git a/libbacktrace/BacktraceThread.h b/libbacktrace/BacktraceThread.h
index 3412d58..ff3e9f3 100644
--- a/libbacktrace/BacktraceThread.h
+++ b/libbacktrace/BacktraceThread.h
@@ -18,73 +18,71 @@
 #define _LIBBACKTRACE_BACKTRACE_THREAD_H
 
 #include <inttypes.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
 #include <sys/types.h>
+#include <ucontext.h>
 
 #include "BacktraceImpl.h"
 
-enum state_e {
-  STATE_WAITING = 0,
-  STATE_DUMPING,
-  STATE_DONE,
-  STATE_CANCEL,
-};
+// The signal used to cause a thread to dump the stack.
+#if defined(__GLIBC__)
+// GLIBC reserves __SIGRTMIN signals, so use SIGRTMIN to avoid errors.
+#define THREAD_SIGNAL SIGRTMIN
+#else
+#define THREAD_SIGNAL (__SIGRTMIN+1)
+#endif
 
-class BacktraceThreadInterface;
+class ThreadEntry {
+public:
+  static ThreadEntry* Get(pid_t pid, pid_t tid, bool create = true);
 
-struct ThreadEntry {
-  ThreadEntry(
-      BacktraceThreadInterface* impl, pid_t pid, pid_t tid,
-      size_t num_ignore_frames);
+  static void Remove(ThreadEntry* entry);
+
+  void Wake();
+
+  void Wait(int);
+
+  void CopyUcontextFromSigcontext(void*);
+
+  inline void Lock() {
+    pthread_mutex_lock(&mutex_);
+    // Reset the futex value in case of multiple unwinds of the same thread.
+    futex_ = 0;
+  }
+
+  inline void Unlock() {
+    pthread_mutex_unlock(&mutex_);
+  }
+
+  inline ucontext_t* GetUcontext() { return &ucontext_; }
+
+private:
+  ThreadEntry(pid_t pid, pid_t tid);
   ~ThreadEntry();
 
-  bool Match(pid_t chk_pid, pid_t chk_tid) { return (chk_pid == pid && chk_tid == tid); }
+  bool Match(pid_t chk_pid, pid_t chk_tid) { return (chk_pid == pid_ && chk_tid == tid_); }
 
-  static ThreadEntry* AddThreadToUnwind(
-      BacktraceThreadInterface* thread_intf, pid_t pid, pid_t tid,
-      size_t num_ignored_frames);
+  pid_t pid_;
+  pid_t tid_;
+  int futex_;
+  int ref_count_;
+  pthread_mutex_t mutex_;
+  ThreadEntry* next_;
+  ThreadEntry* prev_;
+  ucontext_t ucontext_;
 
-  BacktraceThreadInterface* thread_intf;
-  pid_t pid;
-  pid_t tid;
-  ThreadEntry* next;
-  ThreadEntry* prev;
-  int32_t state;
-  int num_ignore_frames;
-};
-
-// Interface class that does not contain any local storage, only defines
-// virtual functions to be defined by subclasses.
-class BacktraceThreadInterface {
-public:
-  virtual ~BacktraceThreadInterface() { }
-
-  virtual void ThreadUnwind(
-      siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) = 0;
+  static ThreadEntry* list_;
+  static pthread_mutex_t list_mutex_;
 };
 
 class BacktraceThread : public BacktraceCurrent {
 public:
-  // impl and thread_intf should point to the same object, this allows
-  // the compiler to catch if an implementation does not properly
-  // subclass both.
-  BacktraceThread(
-      BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid,
-      BacktraceMap* map);
+  BacktraceThread(BacktraceImpl* impl, pid_t tid, BacktraceMap* map);
   virtual ~BacktraceThread();
 
-  virtual bool Unwind(size_t num_ignore_frames);
-
-  virtual void ThreadUnwind(
-      siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) {
-    thread_intf_->ThreadUnwind(siginfo, sigcontext, num_ignore_frames);
-  }
-
-private:
-  virtual bool TriggerUnwindOnThread(ThreadEntry* entry);
-
-  virtual void FinishUnwind();
-
-  BacktraceThreadInterface* thread_intf_;
+  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext);
 };
 
 #endif // _LIBBACKTRACE_BACKTRACE_THREAD_H
diff --git a/libbacktrace/Corkscrew.cpp b/libbacktrace/Corkscrew.cpp
deleted file mode 100644
index efeee2e..0000000
--- a/libbacktrace/Corkscrew.cpp
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "libbacktrace"
-
-#include <backtrace/Backtrace.h>
-
-#include <string.h>
-
-#include <backtrace-arch.h>
-#include <corkscrew/backtrace.h>
-
-#ifndef __USE_GNU
-#define __USE_GNU
-#endif
-#include <dlfcn.h>
-
-#include "Corkscrew.h"
-
-//-------------------------------------------------------------------------
-// CorkscrewMap functions.
-//-------------------------------------------------------------------------
-CorkscrewMap::CorkscrewMap(pid_t pid) : BacktraceMap(pid), map_info_(NULL) {
-}
-
-CorkscrewMap::~CorkscrewMap() {
-  if (map_info_) {
-    free_map_info_list(map_info_);
-    map_info_ = NULL;
-  }
-}
-
-bool CorkscrewMap::Build() {
-  map_info_ = load_map_info_list(pid_);
-
-  // Use the information in map_info_ to construct the BacktraceMap data
-  // rather than reparsing /proc/self/maps.
-  map_info_t* cur_map = map_info_;
-  while (cur_map) {
-    backtrace_map_t map;
-    map.start = cur_map->start;
-    map.end = cur_map->end;
-    map.flags = 0;
-    if (cur_map->is_readable) {
-      map.flags |= PROT_READ;
-    }
-    if (cur_map->is_writable) {
-      map.flags |= PROT_WRITE;
-    }
-    if (cur_map->is_executable) {
-      map.flags |= PROT_EXEC;
-    }
-    map.name = cur_map->name;
-
-    // The maps are in descending order, but we want them in ascending order.
-    maps_.push_front(map);
-
-    cur_map = cur_map->next;
-  }
-  return map_info_ != NULL;
-}
-
-//-------------------------------------------------------------------------
-// CorkscrewCommon functions.
-//-------------------------------------------------------------------------
-bool CorkscrewCommon::GenerateFrameData(
-    backtrace_frame_t* cork_frames, ssize_t num_frames) {
-  if (num_frames < 0) {
-    BACK_LOGW("libcorkscrew unwind failed.");
-    return false;
-  }
-
-  std::vector<backtrace_frame_data_t>* frames = GetFrames();
-  frames->resize(num_frames);
-  size_t i = 0;
-  for (std::vector<backtrace_frame_data_t>::iterator it = frames->begin();
-       it != frames->end(); ++it, ++i) {
-    it->num = i;
-    it->pc = cork_frames[i].absolute_pc;
-    it->sp = cork_frames[i].stack_top;
-    it->stack_size = cork_frames[i].stack_size;
-    it->func_offset = 0;
-
-    it->map = FindMap(it->pc);
-    it->func_name = GetFunctionName(it->pc, &it->func_offset);
-  }
-  return true;
-}
-
-//-------------------------------------------------------------------------
-// CorkscrewCurrent functions.
-//-------------------------------------------------------------------------
-CorkscrewCurrent::CorkscrewCurrent() {
-}
-
-CorkscrewCurrent::~CorkscrewCurrent() {
-}
-
-bool CorkscrewCurrent::Unwind(size_t num_ignore_frames) {
-  backtrace_frame_t frames[MAX_BACKTRACE_FRAMES];
-  ssize_t num_frames = unwind_backtrace(frames, num_ignore_frames, MAX_BACKTRACE_FRAMES);
-
-  return GenerateFrameData(frames, num_frames);
-}
-
-std::string CorkscrewCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
-  *offset = 0;
-
-  Dl_info info;
-  const backtrace_map_t* map = FindMap(pc);
-  if (map) {
-    if (dladdr((const void*)pc, &info)) {
-      if (info.dli_sname) {
-        *offset = pc - map->start - (uintptr_t)info.dli_saddr + (uintptr_t)info.dli_fbase;
-        return info.dli_sname;
-      }
-    } else {
-      // dladdr(3) didn't find a symbol; maybe it's static? Look in the ELF file...
-      symbol_table_t* symbol_table = load_symbol_table(map->name.c_str());
-      if (symbol_table) {
-        // First check if we can find the symbol using a relative pc.
-        std::string name;
-        const symbol_t* elf_symbol = find_symbol(symbol_table, pc - map->start);
-        if (elf_symbol) {
-          name = elf_symbol->name;
-          *offset = pc - map->start - elf_symbol->start;
-        } else if ((elf_symbol = find_symbol(symbol_table, pc)) != NULL) {
-          // Found the symbol using the absolute pc.
-          name = elf_symbol->name;
-          *offset = pc - elf_symbol->start;
-        }
-        free_symbol_table(symbol_table);
-        return name;
-      }
-    }
-  }
-  return "";
-}
-
-//-------------------------------------------------------------------------
-// CorkscrewThread functions.
-//-------------------------------------------------------------------------
-CorkscrewThread::CorkscrewThread() {
-}
-
-CorkscrewThread::~CorkscrewThread() {
-}
-
-void CorkscrewThread::ThreadUnwind(
-    siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) {
-  backtrace_frame_t cork_frames[MAX_BACKTRACE_FRAMES];
-  CorkscrewMap* map = static_cast<CorkscrewMap*>(GetMap());
-  ssize_t num_frames = unwind_backtrace_signal_arch(
-      siginfo, sigcontext, map->GetMapInfo(), cork_frames,
-      num_ignore_frames, MAX_BACKTRACE_FRAMES);
-  if (num_frames > 0) {
-    std::vector<backtrace_frame_data_t>* frames = GetFrames();
-    frames->resize(num_frames);
-    size_t i = 0;
-    for (std::vector<backtrace_frame_data_t>::iterator it = frames->begin();
-         it != frames->end(); ++it, ++i) {
-      it->num = i;
-      it->pc = cork_frames[i].absolute_pc;
-      it->sp = cork_frames[i].stack_top;
-      it->stack_size = cork_frames[i].stack_size;
-      it->map = NULL;
-      it->func_offset = 0;
-    }
-  }
-}
-
-//-------------------------------------------------------------------------
-// CorkscrewPtrace functions.
-//-------------------------------------------------------------------------
-CorkscrewPtrace::CorkscrewPtrace() : ptrace_context_(NULL) {
-}
-
-CorkscrewPtrace::~CorkscrewPtrace() {
-  if (ptrace_context_) {
-    free_ptrace_context(ptrace_context_);
-    ptrace_context_ = NULL;
-  }
-}
-
-bool CorkscrewPtrace::Unwind(size_t num_ignore_frames) {
-  ptrace_context_ = load_ptrace_context(Tid());
-
-  backtrace_frame_t frames[MAX_BACKTRACE_FRAMES];
-  ssize_t num_frames = unwind_backtrace_ptrace(
-      Tid(), ptrace_context_, frames, num_ignore_frames, MAX_BACKTRACE_FRAMES);
-
-  return GenerateFrameData(frames, num_frames);
-}
-
-std::string CorkscrewPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
-  // Get information about a different process.
-  const map_info_t* map_info;
-  const symbol_t* symbol;
-  find_symbol_ptrace(ptrace_context_, pc, &map_info, &symbol);
-  char* symbol_name = NULL;
-  if (symbol) {
-    if (map_info) {
-      *offset = pc - map_info->start - symbol->start;
-    }
-    symbol_name = symbol->name;
-    return symbol_name;
-  }
-
-  return "";
-}
-
-//-------------------------------------------------------------------------
-// C++ object creation functions.
-//-------------------------------------------------------------------------
-Backtrace* CreateCurrentObj(BacktraceMap* map) {
-  return new BacktraceCurrent(new CorkscrewCurrent(), map);
-}
-
-Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, BacktraceMap* map) {
-  return new BacktracePtrace(new CorkscrewPtrace(), pid, tid, map);
-}
-
-Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map) {
-  CorkscrewThread* thread_obj = new CorkscrewThread();
-  return new BacktraceThread(thread_obj, thread_obj, tid, map);
-}
-
-//-------------------------------------------------------------------------
-// BacktraceMap create function.
-//-------------------------------------------------------------------------
-BacktraceMap* BacktraceMap::Create(pid_t pid) {
-  BacktraceMap* map = new CorkscrewMap(pid);
-  if (!map->Build()) {
-    delete map;
-    return NULL;
-  }
-  return map;
-}
diff --git a/libbacktrace/Corkscrew.h b/libbacktrace/Corkscrew.h
deleted file mode 100644
index 1633398..0000000
--- a/libbacktrace/Corkscrew.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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 _LIBBACKTRACE_CORKSCREW_H
-#define _LIBBACKTRACE_CORKSCREW_H
-
-#include <inttypes.h>
-
-#include <string>
-
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-
-#include <corkscrew/backtrace.h>
-
-#include "BacktraceImpl.h"
-#include "BacktraceThread.h"
-
-class CorkscrewMap : public BacktraceMap {
-public:
-  CorkscrewMap(pid_t pid);
-  virtual ~CorkscrewMap();
-
-  virtual bool Build();
-
-  map_info_t* GetMapInfo() { return map_info_; }
-
-private:
-  map_info_t* map_info_;
-};
-
-class CorkscrewCommon : public BacktraceImpl {
-public:
-  bool GenerateFrameData(backtrace_frame_t* cork_frames, ssize_t num_frames);
-};
-
-class CorkscrewCurrent : public CorkscrewCommon {
-public:
-  CorkscrewCurrent();
-  virtual ~CorkscrewCurrent();
-
-  virtual bool Unwind(size_t num_ignore_threads);
-
-  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
-};
-
-class CorkscrewThread : public CorkscrewCurrent, public BacktraceThreadInterface {
-public:
-  CorkscrewThread();
-  virtual ~CorkscrewThread();
-
-  virtual void ThreadUnwind(
-      siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames);
-};
-
-class CorkscrewPtrace : public CorkscrewCommon {
-public:
-  CorkscrewPtrace();
-  virtual ~CorkscrewPtrace();
-
-  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
-
-  virtual bool Unwind(size_t num_ignore_threads);
-
-private:
-  ptrace_context_t* ptrace_context_;
-};
-
-#endif // _LIBBACKTRACE_CORKSCREW_H
diff --git a/libbacktrace/GetPss.cpp b/libbacktrace/GetPss.cpp
new file mode 100644
index 0000000..442383b
--- /dev/null
+++ b/libbacktrace/GetPss.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2014 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 <assert.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+// This is an extremely simplified version of libpagemap.
+
+#define _BITS(x, offset, bits) (((x) >> offset) & ((1LL << (bits)) - 1))
+
+#define PAGEMAP_PRESENT(x)     (_BITS(x, 63, 1))
+#define PAGEMAP_SWAPPED(x)     (_BITS(x, 62, 1))
+#define PAGEMAP_SHIFT(x)       (_BITS(x, 55, 6))
+#define PAGEMAP_PFN(x)         (_BITS(x, 0, 55))
+#define PAGEMAP_SWAP_OFFSET(x) (_BITS(x, 5, 50))
+#define PAGEMAP_SWAP_TYPE(x)   (_BITS(x, 0,  5))
+
+static bool ReadData(int fd, unsigned long place, uint64_t *data) {
+  if (lseek(fd, place * sizeof(uint64_t), SEEK_SET) < 0) {
+    return false;
+  }
+  if (read(fd, (void*)data, sizeof(uint64_t)) != (ssize_t)sizeof(uint64_t)) {
+    return false;
+  }
+  return true;
+}
+
+size_t GetPssBytes() {
+  FILE* maps = fopen("/proc/self/maps", "r");
+  assert(maps != NULL);
+
+  int pagecount_fd = open("/proc/kpagecount", O_RDONLY);
+  assert(pagecount_fd >= 0);
+
+  int pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
+  assert(pagemap_fd >= 0);
+
+  char line[4096];
+  size_t total_pss = 0;
+  int pagesize = getpagesize();
+  while (fgets(line, sizeof(line), maps)) {
+    uintptr_t start, end;
+    if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " ", &start, &end) != 2) {
+      total_pss = 0;
+      break;
+    }
+    for (size_t page = start/pagesize; page < end/pagesize; page++) {
+      uint64_t data;
+      if (ReadData(pagemap_fd, page, &data)) {
+        if (PAGEMAP_PRESENT(data) && !PAGEMAP_SWAPPED(data)) {
+          uint64_t count;
+          if (ReadData(pagecount_fd, PAGEMAP_PFN(data), &count)) {
+            total_pss += (count >= 1) ? pagesize / count : 0;
+          }
+        }
+      }
+    }
+  }
+
+  fclose(maps);
+
+  close(pagecount_fd);
+  close(pagemap_fd);
+
+  return total_pss;
+}
diff --git a/libnl_2/cache.c b/libbacktrace/GetPss.h
similarity index 63%
rename from libnl_2/cache.c
rename to libbacktrace/GetPss.h
index c21974d..787c33d 100644
--- a/libnl_2/cache.c
+++ b/libbacktrace/GetPss.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2014 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,24 +14,9 @@
  * limitations under the License.
  */
 
-/* NOTICE: This is a clean room re-implementation of libnl */
+#ifndef _LIBBACKTRACE_GET_PSS_H
+#define _LIBBACKTRACE_GET_PSS_H
 
-#include "netlink/cache.h"
-#include "netlink/object.h"
+size_t GetPssBytes();
 
-void nl_cache_free(struct nl_cache *cache)
-{
-
-}
-
-void nl_cache_clear(struct nl_cache *cache)
-{
-
-}
-
-void nl_cache_remove(struct nl_object *obj)
-{
-
-}
-
-
+#endif // _LIBBACKTRACE_GET_PSS_H
diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp
old mode 100644
new mode 100755
index 17b71b9..b176aaf
--- a/libbacktrace/UnwindCurrent.cpp
+++ b/libbacktrace/UnwindCurrent.cpp
@@ -14,9 +14,8 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "libbacktrace"
-
 #include <sys/types.h>
+#include <ucontext.h>
 
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
@@ -24,30 +23,11 @@
 #define UNW_LOCAL_ONLY
 #include <libunwind.h>
 
+#include "BacktraceLog.h"
+#include "BacktraceThread.h"
 #include "UnwindCurrent.h"
 #include "UnwindMap.h"
 
-// Define the ucontext_t structures needed for each supported arch.
-#if defined(__arm__)
-  // The current version of the <signal.h> doesn't define ucontext_t.
-  #include <asm/sigcontext.h> // Ensure 'struct sigcontext' is defined.
-
-  // Machine context at the time a signal was raised.
-  typedef struct ucontext {
-    uint32_t uc_flags;
-    struct ucontext* uc_link;
-    stack_t uc_stack;
-    struct sigcontext uc_mcontext;
-    uint32_t uc_sigmask;
-  } ucontext_t;
-#elif defined(__i386__)
-  #include <asm/sigcontext.h>
-  #include <asm/ucontext.h>
-  typedef struct ucontext ucontext_t;
-#elif !defined(__mips__) && !defined(__aarch64__)
-  #error Unsupported architecture.
-#endif
-
 //-------------------------------------------------------------------------
 // UnwindCurrent functions.
 //-------------------------------------------------------------------------
@@ -57,13 +37,43 @@
 UnwindCurrent::~UnwindCurrent() {
 }
 
-bool UnwindCurrent::Unwind(size_t num_ignore_frames) {
-  int ret = unw_getcontext(&context_);
-  if (ret < 0) {
-    BACK_LOGW("unw_getcontext failed %d", ret);
-    return false;
+bool UnwindCurrent::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
+  if (!ucontext) {
+    int ret = unw_getcontext(&context_);
+    if (ret < 0) {
+      BACK_LOGW("unw_getcontext failed %d", ret);
+      return false;
+    }
   }
-  return UnwindFromContext(num_ignore_frames, true);
+  else {
+    GetUnwContextFromUcontext(ucontext);
+  }
+  return UnwindFromContext(num_ignore_frames, false);
+}
+
+void UnwindCurrent::GetUnwContextFromUcontext(const ucontext_t* ucontext) {
+  unw_tdep_context_t* unw_context = reinterpret_cast<unw_tdep_context_t*>(&context_);
+
+#if defined(__arm__)
+  unw_context->regs[0] = ucontext->uc_mcontext.arm_r0;
+  unw_context->regs[1] = ucontext->uc_mcontext.arm_r1;
+  unw_context->regs[2] = ucontext->uc_mcontext.arm_r2;
+  unw_context->regs[3] = ucontext->uc_mcontext.arm_r3;
+  unw_context->regs[4] = ucontext->uc_mcontext.arm_r4;
+  unw_context->regs[5] = ucontext->uc_mcontext.arm_r5;
+  unw_context->regs[6] = ucontext->uc_mcontext.arm_r6;
+  unw_context->regs[7] = ucontext->uc_mcontext.arm_r7;
+  unw_context->regs[8] = ucontext->uc_mcontext.arm_r8;
+  unw_context->regs[9] = ucontext->uc_mcontext.arm_r9;
+  unw_context->regs[10] = ucontext->uc_mcontext.arm_r10;
+  unw_context->regs[11] = ucontext->uc_mcontext.arm_fp;
+  unw_context->regs[12] = ucontext->uc_mcontext.arm_ip;
+  unw_context->regs[13] = ucontext->uc_mcontext.arm_sp;
+  unw_context->regs[14] = ucontext->uc_mcontext.arm_lr;
+  unw_context->regs[15] = ucontext->uc_mcontext.arm_pc;
+#else
+  unw_context->uc_mcontext = ucontext->uc_mcontext;
+#endif
 }
 
 std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
@@ -78,12 +88,14 @@
   return "";
 }
 
-bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool resolve) {
+bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool within_handler) {
   // The cursor structure is pretty large, do not put it on the stack.
   unw_cursor_t* cursor = new unw_cursor_t;
   int ret = unw_init_local(cursor, &context_);
   if (ret < 0) {
-    BACK_LOGW("unw_init_local failed %d", ret);
+    if (!within_handler) {
+      BACK_LOGW("unw_init_local failed %d", ret);
+    }
     delete cursor;
     return false;
   }
@@ -95,13 +107,17 @@
     unw_word_t pc;
     ret = unw_get_reg(cursor, UNW_REG_IP, &pc);
     if (ret < 0) {
-      BACK_LOGW("Failed to read IP %d", ret);
+      if (!within_handler) {
+        BACK_LOGW("Failed to read IP %d", ret);
+      }
       break;
     }
     unw_word_t sp;
     ret = unw_get_reg(cursor, UNW_REG_SP, &sp);
     if (ret < 0) {
-      BACK_LOGW("Failed to read SP %d", ret);
+      if (!within_handler) {
+        BACK_LOGW("Failed to read SP %d", ret);
+      }
       break;
     }
 
@@ -119,7 +135,7 @@
         prev->stack_size = frame->sp - prev->sp;
       }
 
-      if (resolve) {
+      if (!within_handler) {
         frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
         frame->map = FindMap(frame->pc);
       } else {
@@ -137,47 +153,6 @@
   return true;
 }
 
-void UnwindCurrent::ExtractContext(void* sigcontext) {
-  unw_tdep_context_t* context = reinterpret_cast<unw_tdep_context_t*>(&context_);
-  const ucontext_t* uc = reinterpret_cast<const ucontext_t*>(sigcontext);
-
-#if defined(__arm__)
-  context->regs[0] = uc->uc_mcontext.arm_r0;
-  context->regs[1] = uc->uc_mcontext.arm_r1;
-  context->regs[2] = uc->uc_mcontext.arm_r2;
-  context->regs[3] = uc->uc_mcontext.arm_r3;
-  context->regs[4] = uc->uc_mcontext.arm_r4;
-  context->regs[5] = uc->uc_mcontext.arm_r5;
-  context->regs[6] = uc->uc_mcontext.arm_r6;
-  context->regs[7] = uc->uc_mcontext.arm_r7;
-  context->regs[8] = uc->uc_mcontext.arm_r8;
-  context->regs[9] = uc->uc_mcontext.arm_r9;
-  context->regs[10] = uc->uc_mcontext.arm_r10;
-  context->regs[11] = uc->uc_mcontext.arm_fp;
-  context->regs[12] = uc->uc_mcontext.arm_ip;
-  context->regs[13] = uc->uc_mcontext.arm_sp;
-  context->regs[14] = uc->uc_mcontext.arm_lr;
-  context->regs[15] = uc->uc_mcontext.arm_pc;
-#elif defined(__mips__) || defined(__i386__)
-  context->uc_mcontext = uc->uc_mcontext;
-#endif
-}
-
-//-------------------------------------------------------------------------
-// UnwindThread functions.
-//-------------------------------------------------------------------------
-UnwindThread::UnwindThread() {
-}
-
-UnwindThread::~UnwindThread() {
-}
-
-void UnwindThread::ThreadUnwind(
-    siginfo_t* /*siginfo*/, void* sigcontext, size_t num_ignore_frames) {
-  ExtractContext(sigcontext);
-  UnwindFromContext(num_ignore_frames, false);
-}
-
 //-------------------------------------------------------------------------
 // C++ object creation function.
 //-------------------------------------------------------------------------
@@ -186,6 +161,5 @@
 }
 
 Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map) {
-  UnwindThread* thread_obj = new UnwindThread();
-  return new BacktraceThread(thread_obj, thread_obj, tid, map);
+  return new BacktraceThread(new UnwindCurrent(), tid, map);
 }
diff --git a/libbacktrace/UnwindCurrent.h b/libbacktrace/UnwindCurrent.h
index acce110..2375e6e 100644
--- a/libbacktrace/UnwindCurrent.h
+++ b/libbacktrace/UnwindCurrent.h
@@ -20,7 +20,6 @@
 #include <string>
 
 #include "BacktraceImpl.h"
-#include "BacktraceThread.h"
 
 #define UNW_LOCAL_ONLY
 #include <libunwind.h>
@@ -30,25 +29,16 @@
   UnwindCurrent();
   virtual ~UnwindCurrent();
 
-  virtual bool Unwind(size_t num_ignore_frames);
+  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext);
 
   virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
 
-  bool UnwindFromContext(size_t num_ignore_frames, bool resolve);
+  bool UnwindFromContext(size_t num_ignore_frames, bool within_handler);
 
-  void ExtractContext(void* sigcontext);
+  void GetUnwContextFromUcontext(const ucontext_t* context);
 
 protected:
   unw_context_t context_;
 };
 
-class UnwindThread : public UnwindCurrent, public BacktraceThreadInterface {
-public:
-  UnwindThread();
-  virtual ~UnwindThread();
-
-  virtual void ThreadUnwind(
-      siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames);
-};
-
 #endif // _LIBBACKTRACE_UNWIND_CURRENT_H
diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp
index 03bb192..4f9831b 100644
--- a/libbacktrace/UnwindMap.cpp
+++ b/libbacktrace/UnwindMap.cpp
@@ -14,9 +14,8 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "libbacktrace"
-
 #include <pthread.h>
+#include <stdlib.h>
 #include <sys/types.h>
 #include <unistd.h>
 
@@ -24,6 +23,7 @@
 
 #include <libunwind.h>
 
+#include "BacktraceLog.h"
 #include "UnwindMap.h"
 
 //-------------------------------------------------------------------------
@@ -32,57 +32,21 @@
 // only update the local address space once, and keep a reference count
 // of maps using the same map cursor.
 //-------------------------------------------------------------------------
-static pthread_mutex_t g_map_mutex = PTHREAD_MUTEX_INITIALIZER;
-static unw_map_cursor_t g_map_cursor;
-static int g_map_references = 0;
-
 UnwindMap::UnwindMap(pid_t pid) : BacktraceMap(pid) {
-  map_cursor_.map_list = NULL;
 }
 
 UnwindMap::~UnwindMap() {
-  if (pid_ == getpid()) {
-    pthread_mutex_lock(&g_map_mutex);
-    if (--g_map_references == 0) {
-      // Clear the local address space map.
-      unw_map_set(unw_local_addr_space, NULL);
-      unw_map_cursor_destroy(&map_cursor_);
-    }
-    pthread_mutex_unlock(&g_map_mutex);
-  } else {
-    unw_map_cursor_destroy(&map_cursor_);
-  }
+  unw_map_cursor_destroy(&map_cursor_);
+  unw_map_cursor_clear(&map_cursor_);
 }
 
-bool UnwindMap::Build() {
-  bool return_value = true;
-  if (pid_ == getpid()) {
-    pthread_mutex_lock(&g_map_mutex);
-    if (g_map_references == 0) {
-      return_value = (unw_map_cursor_create(&map_cursor_, pid_) == 0);
-      if (return_value) {
-        // Set the local address space to this cursor map.
-        unw_map_set(unw_local_addr_space, &map_cursor_);
-        g_map_references = 1;
-        g_map_cursor = map_cursor_;
-      }
-    } else {
-      g_map_references++;
-      map_cursor_ = g_map_cursor;
-    }
-    pthread_mutex_unlock(&g_map_mutex);
-  } else {
-    return_value = (unw_map_cursor_create(&map_cursor_, pid_) == 0);
-  }
-
-  if (!return_value)
-    return false;
-
+bool UnwindMap::GenerateMap() {
   // Use the map_cursor information to construct the BacktraceMap data
   // rather than reparsing /proc/self/maps.
   unw_map_cursor_reset(&map_cursor_);
+
   unw_map_t unw_map;
-  while (unw_map_cursor_get(&map_cursor_, &unw_map)) {
+  while (unw_map_cursor_get_next(&map_cursor_, &unw_map)) {
     backtrace_map_t map;
 
     map.start = unw_map.start;
@@ -97,11 +61,82 @@
   return true;
 }
 
+bool UnwindMap::Build() {
+  return (unw_map_cursor_create(&map_cursor_, pid_) == 0) && GenerateMap();
+}
+
+UnwindMapLocal::UnwindMapLocal() : UnwindMap(getpid()), map_created_(false) {
+}
+
+UnwindMapLocal::~UnwindMapLocal() {
+  if (map_created_) {
+    unw_map_local_destroy();
+    unw_map_cursor_clear(&map_cursor_);
+  }
+}
+
+bool UnwindMapLocal::GenerateMap() {
+  // It's possible for the map to be regenerated while this loop is occurring.
+  // If that happens, get the map again, but only try at most three times
+  // before giving up.
+  for (int i = 0; i < 3; i++) {
+    maps_.clear();
+
+    unw_map_local_cursor_get(&map_cursor_);
+
+    unw_map_t unw_map;
+    int ret;
+    while ((ret = unw_map_local_cursor_get_next(&map_cursor_, &unw_map)) > 0) {
+      backtrace_map_t map;
+
+      map.start = unw_map.start;
+      map.end = unw_map.end;
+      map.flags = unw_map.flags;
+      map.name = unw_map.path;
+
+      free(unw_map.path);
+
+      // The maps are in descending order, but we want them in ascending order.
+      maps_.push_front(map);
+    }
+    // Check to see if the map changed while getting the data.
+    if (ret != -UNW_EINVAL) {
+      return true;
+    }
+  }
+
+  BACK_LOGW("Unable to generate the map.");
+  return false;
+}
+
+bool UnwindMapLocal::Build() {
+  return (map_created_ = (unw_map_local_create() == 0)) && GenerateMap();;
+}
+
+const backtrace_map_t* UnwindMapLocal::Find(uintptr_t addr) {
+  const backtrace_map_t* map = BacktraceMap::Find(addr);
+  if (!map) {
+    // Check to see if the underlying map changed and regenerate the map
+    // if it did.
+    if (unw_map_local_cursor_valid(&map_cursor_) < 0) {
+      if (GenerateMap()) {
+        map = BacktraceMap::Find(addr);
+      }
+    }
+  }
+  return map;
+}
+
 //-------------------------------------------------------------------------
 // BacktraceMap create function.
 //-------------------------------------------------------------------------
 BacktraceMap* BacktraceMap::Create(pid_t pid) {
-  BacktraceMap* map = new UnwindMap(pid);
+  BacktraceMap* map;
+  if (pid == getpid()) {
+    map = new UnwindMapLocal();
+  } else {
+    map = new UnwindMap(pid);
+  }
   if (!map->Build()) {
     delete map;
     return NULL;
diff --git a/libbacktrace/UnwindMap.h b/libbacktrace/UnwindMap.h
index 5a874e8..2fdb29f 100644
--- a/libbacktrace/UnwindMap.h
+++ b/libbacktrace/UnwindMap.h
@@ -32,8 +32,25 @@
 
   unw_map_cursor_t* GetMapCursor() { return &map_cursor_; }
 
-private:
+protected:
+  virtual bool GenerateMap();
+
   unw_map_cursor_t map_cursor_;
 };
 
+class UnwindMapLocal : public UnwindMap {
+public:
+  UnwindMapLocal();
+  virtual ~UnwindMapLocal();
+
+  virtual bool Build();
+
+  virtual const backtrace_map_t* Find(uintptr_t addr);
+
+protected:
+  virtual bool GenerateMap();
+
+  bool map_created_;
+};
+
 #endif // _LIBBACKTRACE_UNWIND_MAP_H
diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp
index 732dae8..7ba8775 100644
--- a/libbacktrace/UnwindPtrace.cpp
+++ b/libbacktrace/UnwindPtrace.cpp
@@ -14,17 +14,17 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "libbacktrace"
-
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 
 #include <sys/types.h>
 #include <string.h>
+#include <ucontext.h>
 
 #include <libunwind.h>
 #include <libunwind-ptrace.h>
 
+#include "BacktraceLog.h"
 #include "UnwindMap.h"
 #include "UnwindPtrace.h"
 
@@ -46,7 +46,12 @@
   }
 }
 
-bool UnwindPtrace::Unwind(size_t num_ignore_frames) {
+bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
+  if (ucontext) {
+    BACK_LOGW("Unwinding from a specified context not supported yet.");
+    return false;
+  }
+
   addr_space_ = unw_create_addr_space(&_UPT_accessors, 0);
   if (!addr_space_) {
     BACK_LOGW("unw_create_addr_space failed.");
diff --git a/libbacktrace/UnwindPtrace.h b/libbacktrace/UnwindPtrace.h
index 1e82117..2fb7967 100644
--- a/libbacktrace/UnwindPtrace.h
+++ b/libbacktrace/UnwindPtrace.h
@@ -28,7 +28,7 @@
   UnwindPtrace();
   virtual ~UnwindPtrace();
 
-  virtual bool Unwind(size_t num_ignore_frames);
+  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext);
 
   virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
 
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 23eaf92..ed6b211 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -16,9 +16,10 @@
 
 #include <dirent.h>
 #include <errno.h>
+#include <inttypes.h>
 #include <pthread.h>
 #include <signal.h>
-#include <stdbool.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -32,9 +33,13 @@
 #include <backtrace/BacktraceMap.h>
 #include <UniquePtr.h>
 
+// For the THREAD_SIGNAL definition.
+#include "BacktraceThread.h"
+
 #include <cutils/atomic.h>
 #include <gtest/gtest.h>
 
+#include <algorithm>
 #include <vector>
 
 #include "thread_utils.h"
@@ -287,7 +292,7 @@
   pid_t pid;
   if ((pid = fork()) == 0) {
     ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
-    exit(1);
+    _exit(1);
   }
   VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyLevelBacktrace, VerifyLevelDump);
 
@@ -300,7 +305,7 @@
   pid_t pid;
   if ((pid = fork()) == 0) {
     ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
-    exit(1);
+    _exit(1);
   }
 
   VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, true, ReadyLevelBacktrace, VerifyLevelDump);
@@ -314,7 +319,7 @@
   pid_t pid;
   if ((pid = fork()) == 0) {
     ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, NULL, NULL), 0);
-    exit(1);
+    _exit(1);
   }
   VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyMaxBacktrace, VerifyMaxDump);
 
@@ -339,7 +344,7 @@
   pid_t pid;
   if ((pid = fork()) == 0) {
     ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
-    exit(1);
+    _exit(1);
   }
   VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyLevelBacktrace, VerifyProcessIgnoreFrames);
 
@@ -384,7 +389,7 @@
       ASSERT_TRUE(pthread_create(&thread, &attr, PtraceThreadLevelRun, NULL) == 0);
     }
     ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
-    exit(1);
+    _exit(1);
   }
 
   // Check to see that all of the threads are running before unwinding.
@@ -458,9 +463,15 @@
   // Wait up to 2 seconds for the tid to be set.
   ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
 
+  // Make sure that the thread signal used is not visible when compiled for
+  // the target.
+#if !defined(__GLIBC__)
+  ASSERT_LT(THREAD_SIGNAL, SIGRTMIN);
+#endif
+
   // Save the current signal action and make sure it is restored afterwards.
   struct sigaction cur_action;
-  ASSERT_TRUE(sigaction(SIGURG, NULL, &cur_action) == 0);
+  ASSERT_TRUE(sigaction(THREAD_SIGNAL, NULL, &cur_action) == 0);
 
   UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
   ASSERT_TRUE(backtrace.get() != NULL);
@@ -473,7 +484,7 @@
 
   // Verify that the old action was restored.
   struct sigaction new_action;
-  ASSERT_TRUE(sigaction(SIGURG, NULL, &new_action) == 0);
+  ASSERT_TRUE(sigaction(THREAD_SIGNAL, NULL, &new_action) == 0);
   EXPECT_EQ(cur_action.sa_sigaction, new_action.sa_sigaction);
   EXPECT_EQ(cur_action.sa_flags, new_action.sa_flags);
 }
@@ -604,6 +615,49 @@
   }
 }
 
+TEST(libbacktrace, thread_multiple_dump_same_thread) {
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+  thread_t runner;
+  runner.tid = 0;
+  runner.state = 0;
+  ASSERT_TRUE(pthread_create(&runner.threadId, &attr, ThreadMaxRun, &runner) == 0);
+
+  // Wait for tids to be set.
+  ASSERT_TRUE(WaitForNonZero(&runner.state, 10));
+
+  // Start all of the dumpers at once, they will spin until they are signalled
+  // to begin their dump run.
+  int32_t dump_now = 0;
+  // Dump the same thread NUM_THREADS simultaneously.
+  std::vector<dump_thread_t> dumpers(NUM_THREADS);
+  for (size_t i = 0; i < NUM_THREADS; i++) {
+    dumpers[i].thread.tid = runner.tid;
+    dumpers[i].thread.state = 0;
+    dumpers[i].done = 0;
+    dumpers[i].now = &dump_now;
+
+    ASSERT_TRUE(pthread_create(&dumpers[i].thread.threadId, &attr, ThreadDump, &dumpers[i]) == 0);
+  }
+
+  // Start all of the dumpers going at once.
+  android_atomic_acquire_store(1, &dump_now);
+
+  for (size_t i = 0; i < NUM_THREADS; i++) {
+    ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 100));
+
+    ASSERT_TRUE(dumpers[i].backtrace != NULL);
+    VerifyMaxDump(dumpers[i].backtrace);
+
+    delete dumpers[i].backtrace;
+    dumpers[i].backtrace = NULL;
+  }
+
+  // Tell the runner thread to exit its infinite loop.
+  android_atomic_acquire_store(0, &runner.state);
+}
+
 // This test is for UnwindMaps that should share the same map cursor when
 // multiple maps are created for the current process at the same time.
 TEST(libbacktrace, simultaneous_maps) {
@@ -693,3 +747,136 @@
 #endif
             backtrace->FormatFrameData(&frame));
 }
+
+struct map_test_t {
+  uintptr_t start;
+  uintptr_t end;
+};
+
+bool map_sort(map_test_t i, map_test_t j) {
+  return i.start < j.start;
+}
+
+static void VerifyMap(pid_t pid) {
+  char buffer[4096];
+  snprintf(buffer, sizeof(buffer), "/proc/%d/maps", pid);
+
+  FILE* map_file = fopen(buffer, "r");
+  ASSERT_TRUE(map_file != NULL);
+  std::vector<map_test_t> test_maps;
+  while (fgets(buffer, sizeof(buffer), map_file)) {
+    map_test_t map;
+    ASSERT_EQ(2, sscanf(buffer, "%" SCNxPTR "-%" SCNxPTR " ", &map.start, &map.end));
+    test_maps.push_back(map);
+  }
+  fclose(map_file);
+  std::sort(test_maps.begin(), test_maps.end(), map_sort);
+
+  UniquePtr<BacktraceMap> map(BacktraceMap::Create(pid));
+
+  // Basic test that verifies that the map is in the expected order.
+  std::vector<map_test_t>::const_iterator test_it = test_maps.begin();
+  for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
+    ASSERT_TRUE(test_it != test_maps.end());
+    ASSERT_EQ(test_it->start, it->start);
+    ASSERT_EQ(test_it->end, it->end);
+    ++test_it;
+  }
+  ASSERT_TRUE(test_it == test_maps.end());
+}
+
+TEST(libbacktrace, verify_map_remote) {
+  pid_t pid;
+
+  if ((pid = fork()) == 0) {
+    while (true) {
+    }
+    _exit(0);
+  }
+  ASSERT_LT(0, pid);
+
+  ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
+
+  // Wait for the process to get to a stopping point.
+  WaitForStop(pid);
+
+  // The maps should match exactly since the forked process has been paused.
+  VerifyMap(pid);
+
+  ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
+
+  kill(pid, SIGKILL);
+  ASSERT_EQ(waitpid(pid, NULL, 0), pid);
+}
+
+#if defined(ENABLE_PSS_TESTS)
+#include "GetPss.h"
+
+#define MAX_LEAK_BYTES 32*1024UL
+
+static void CheckForLeak(pid_t pid, pid_t tid) {
+  // Do a few runs to get the PSS stable.
+  for (size_t i = 0; i < 100; i++) {
+    Backtrace* backtrace = Backtrace::Create(pid, tid);
+    ASSERT_TRUE(backtrace != NULL);
+    ASSERT_TRUE(backtrace->Unwind(0));
+    delete backtrace;
+  }
+  size_t stable_pss = GetPssBytes();
+
+  // Loop enough that even a small leak should be detectable.
+  for (size_t i = 0; i < 4096; i++) {
+    Backtrace* backtrace = Backtrace::Create(pid, tid);
+    ASSERT_TRUE(backtrace != NULL);
+    ASSERT_TRUE(backtrace->Unwind(0));
+    delete backtrace;
+  }
+  size_t new_pss = GetPssBytes();
+  size_t abs_diff = (new_pss > stable_pss) ? new_pss - stable_pss : stable_pss - new_pss;
+  // As long as the new pss is within a certain amount, consider everything okay.
+  ASSERT_LE(abs_diff, MAX_LEAK_BYTES);
+}
+
+TEST(libbacktrace, check_for_leak_local) {
+  CheckForLeak(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD);
+}
+
+TEST(libbacktrace, check_for_leak_local_thread) {
+  thread_t thread_data = { 0, 0, 0 };
+  pthread_t thread;
+  ASSERT_TRUE(pthread_create(&thread, NULL, ThreadLevelRun, &thread_data) == 0);
+
+  // Wait up to 2 seconds for the tid to be set.
+  ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
+
+  CheckForLeak(BACKTRACE_CURRENT_PROCESS, thread_data.tid);
+
+  // Tell the thread to exit its infinite loop.
+  android_atomic_acquire_store(0, &thread_data.state);
+
+  ASSERT_TRUE(pthread_join(thread, NULL) == 0);
+}
+
+TEST(libbacktrace, check_for_leak_remote) {
+  pid_t pid;
+
+  if ((pid = fork()) == 0) {
+    while (true) {
+    }
+    _exit(0);
+  }
+  ASSERT_LT(0, pid);
+
+  ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
+
+  // Wait for the process to get to a stopping point.
+  WaitForStop(pid);
+
+  CheckForLeak(pid, BACKTRACE_CURRENT_THREAD);
+
+  ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
+
+  kill(pid, SIGKILL);
+  ASSERT_EQ(waitpid(pid, NULL, 0), pid);
+}
+#endif
diff --git a/libcorkscrew/Android.mk b/libcorkscrew/Android.mk
deleted file mode 100644
index e275317..0000000
--- a/libcorkscrew/Android.mk
+++ /dev/null
@@ -1,98 +0,0 @@
-# Copyright (C) 2011 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-generic_src_files := \
-	backtrace.c \
-	backtrace-helper.c \
-	demangle.c \
-	map_info.c \
-	ptrace.c \
-	symbol_table.c
-
-arm_src_files := \
-	arch-arm/backtrace-arm.c \
-	arch-arm/ptrace-arm.c
-
-x86_src_files := \
-	arch-x86/backtrace-x86.c \
-	arch-x86/ptrace-x86.c
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(generic_src_files)
-
-ifeq ($(TARGET_ARCH),arm)
-LOCAL_SRC_FILES += $(arm_src_files)
-LOCAL_CFLAGS += -DCORKSCREW_HAVE_ARCH
-endif
-ifeq ($(TARGET_ARCH),x86)
-LOCAL_SRC_FILES += $(x86_src_files)
-LOCAL_CFLAGS += -DCORKSCREW_HAVE_ARCH
-endif
-ifeq ($(TARGET_ARCH),mips)
-LOCAL_SRC_FILES += \
-	arch-mips/backtrace-mips.c \
-	arch-mips/ptrace-mips.c
-LOCAL_CFLAGS += -DCORKSCREW_HAVE_ARCH
-endif
-
-LOCAL_SHARED_LIBRARIES += libdl libcutils liblog libgccdemangle
-
-LOCAL_CFLAGS += -std=gnu99 -Werror -Wno-unused-parameter
-LOCAL_MODULE := libcorkscrew
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-# Build test.
-include $(CLEAR_VARS)
-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_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.cpp
-LOCAL_CFLAGS += -Werror
-LOCAL_SHARED_LIBRARIES := libcorkscrew
-LOCAL_MODULE := libcorkscrew_test
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_HOST_EXECUTABLE)
-
-endif # HOST_ARCH == x86
diff --git a/libcorkscrew/MODULE_LICENSE_APACHE2 b/libcorkscrew/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/libcorkscrew/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/libcorkscrew/NOTICE b/libcorkscrew/NOTICE
deleted file mode 100644
index becc120..0000000
--- a/libcorkscrew/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
-   Copyright (c) 2011, The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-
-   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.
-
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
diff --git a/libcorkscrew/arch-arm/backtrace-arm.c b/libcorkscrew/arch-arm/backtrace-arm.c
deleted file mode 100644
index 7bd0d8f..0000000
--- a/libcorkscrew/arch-arm/backtrace-arm.c
+++ /dev/null
@@ -1,601 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Backtracing functions for ARM.
- *
- * This implementation uses the exception unwinding tables provided by
- * the compiler to unwind call frames.  Refer to the ARM Exception Handling ABI
- * documentation (EHABI) for more details about what's going on here.
- *
- * An ELF binary may contain an EXIDX section that provides an index to
- * the exception handling table of each function, sorted by program
- * counter address.
- *
- * This implementation also supports unwinding other processes via ptrace().
- * In that case, the EXIDX section is found by reading the ELF section table
- * structures using ptrace().
- *
- * Because the tables are used for exception handling, it can happen that
- * a given function will not have an exception handling table.  In particular,
- * exceptions are assumed to only ever be thrown at call sites.  Therefore,
- * by definition leaf functions will not have exception handling tables.
- * This may make unwinding impossible in some cases although we can still get
- * some idea of the call stack by examining the PC and LR registers.
- *
- * As we are only interested in backtrace information, we do not need
- * to perform all of the work of unwinding such as restoring register
- * state and running cleanup functions.  Unwinding is performed virtually on
- * an abstract machine context consisting of just the ARM core registers.
- * Furthermore, we do not run generic "personality functions" because
- * we may not be in a position to execute arbitrary code, especially if
- * we are running in a signal handler or using ptrace()!
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include "../backtrace-arch.h"
-#include "../backtrace-helper.h"
-#include "../ptrace-arch.h"
-#include <corkscrew/ptrace.h>
-
-#include <stdlib.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <limits.h>
-#include <errno.h>
-#include <sys/ptrace.h>
-#include <elf.h>
-#include <cutils/log.h>
-
-#if !defined(__BIONIC_HAVE_UCONTEXT_T)
-/* Old versions of the Android <signal.h> didn't define ucontext_t. */
-#include <asm/sigcontext.h> /* Ensure 'struct sigcontext' is defined. */
-
-/* Machine context at the time a signal was raised. */
-typedef struct ucontext {
-    uint32_t uc_flags;
-    struct ucontext* uc_link;
-    stack_t uc_stack;
-    struct sigcontext uc_mcontext;
-    uint32_t uc_sigmask;
-} ucontext_t;
-#endif /* !__BIONIC_HAVE_UCONTEXT_T */
-
-/* Unwind state. */
-typedef struct {
-    uint32_t gregs[16];
-} unwind_state_t;
-
-static const int R_SP = 13;
-static const int R_LR = 14;
-static const int R_PC = 15;
-
-/* Special EXIDX value that indicates that a frame cannot be unwound. */
-static const uint32_t EXIDX_CANTUNWIND = 1;
-
-/* Get the EXIDX section start and size for the module that contains a
- * given program counter address.
- *
- * When the executable is statically linked, the EXIDX section can be
- * accessed by querying the values of the __exidx_start and __exidx_end
- * symbols.
- *
- * When the executable is dynamically linked, the linker exports a function
- * called dl_unwind_find_exidx that obtains the EXIDX section for a given
- * absolute program counter address.
- *
- * Bionic exports a helpful function called __gnu_Unwind_Find_exidx that
- * handles both cases, so we use that here.
- */
-typedef long unsigned int* _Unwind_Ptr;
-extern _Unwind_Ptr __gnu_Unwind_Find_exidx(_Unwind_Ptr pc, int *pcount);
-
-static uintptr_t find_exidx(uintptr_t pc, size_t* out_exidx_size) {
-    int count;
-    uintptr_t start = (uintptr_t)__gnu_Unwind_Find_exidx((_Unwind_Ptr)pc, &count);
-    *out_exidx_size = count;
-    return start;
-}
-
-/* Transforms a 31-bit place-relative offset to an absolute address.
- * We assume the most significant bit is clear. */
-static uintptr_t prel_to_absolute(uintptr_t place, uint32_t prel_offset) {
-    return place + (((int32_t)(prel_offset << 1)) >> 1);
-}
-
-static uintptr_t get_exception_handler(const memory_t* memory,
-        const map_info_t* map_info_list, uintptr_t pc) {
-    if (!pc) {
-        ALOGV("get_exception_handler: pc is zero, no handler");
-        return 0;
-    }
-
-    uintptr_t exidx_start;
-    size_t exidx_size;
-    const map_info_t* mi;
-    if (memory->tid < 0) {
-        mi = NULL;
-        exidx_start = find_exidx(pc, &exidx_size);
-    } else {
-        mi = find_map_info(map_info_list, pc);
-        if (mi && mi->data) {
-            const map_info_data_t* data = (const map_info_data_t*)mi->data;
-            exidx_start = data->exidx_start;
-            exidx_size = data->exidx_size;
-        } else {
-            exidx_start = 0;
-            exidx_size = 0;
-        }
-    }
-
-    uintptr_t handler = 0;
-    int32_t handler_index = -1;
-    if (exidx_start) {
-        uint32_t low = 0;
-        uint32_t high = exidx_size;
-        while (low < high) {
-            uint32_t index = (low + high) / 2;
-            uintptr_t entry = exidx_start + index * 8;
-            uint32_t entry_prel_pc;
-            ALOGV("XXX low=%u, high=%u, index=%u", low, high, index);
-            if (!try_get_word(memory, entry, &entry_prel_pc)) {
-                break;
-            }
-            uintptr_t entry_pc = prel_to_absolute(entry, entry_prel_pc);
-            ALOGV("XXX entry_pc=0x%08x", entry_pc);
-            if (pc < entry_pc) {
-                high = index;
-                continue;
-            }
-            if (index + 1 < exidx_size) {
-                uintptr_t next_entry = entry + 8;
-                uint32_t next_entry_prel_pc;
-                if (!try_get_word(memory, next_entry, &next_entry_prel_pc)) {
-                    break;
-                }
-                uintptr_t next_entry_pc = prel_to_absolute(next_entry, next_entry_prel_pc);
-                ALOGV("XXX next_entry_pc=0x%08x", next_entry_pc);
-                if (pc >= next_entry_pc) {
-                    low = index + 1;
-                    continue;
-                }
-            }
-
-            uintptr_t entry_handler_ptr = entry + 4;
-            uint32_t entry_handler;
-            if (!try_get_word(memory, entry_handler_ptr, &entry_handler)) {
-                break;
-            }
-            if (entry_handler & (1L << 31)) {
-                handler = entry_handler_ptr; // in-place handler data
-            } else if (entry_handler != EXIDX_CANTUNWIND) {
-                handler = prel_to_absolute(entry_handler_ptr, entry_handler);
-            }
-            handler_index = index;
-            break;
-        }
-    }
-    if (mi) {
-        ALOGV("get_exception_handler: pc=0x%08x, module='%s', module_start=0x%08x, "
-                "exidx_start=0x%08x, exidx_size=%d, handler=0x%08x, handler_index=%d",
-                pc, mi->name, mi->start, exidx_start, exidx_size, handler, handler_index);
-    } else {
-        ALOGV("get_exception_handler: pc=0x%08x, "
-                "exidx_start=0x%08x, exidx_size=%d, handler=0x%08x, handler_index=%d",
-                pc, exidx_start, exidx_size, handler, handler_index);
-    }
-    return handler;
-}
-
-typedef struct {
-    uintptr_t ptr;
-    uint32_t word;
-} byte_stream_t;
-
-static bool try_next_byte(const memory_t* memory, byte_stream_t* stream, uint8_t* out_value) {
-    uint8_t result;
-    switch (stream->ptr & 3) {
-    case 0:
-        if (!try_get_word(memory, stream->ptr, &stream->word)) {
-            *out_value = 0;
-            return false;
-        }
-        *out_value = stream->word >> 24;
-        break;
-
-    case 1:
-        *out_value = stream->word >> 16;
-        break;
-
-    case 2:
-        *out_value = stream->word >> 8;
-        break;
-
-    default:
-        *out_value = stream->word;
-        break;
-    }
-
-    ALOGV("next_byte: ptr=0x%08x, value=0x%02x", stream->ptr, *out_value);
-    stream->ptr += 1;
-    return true;
-}
-
-static void set_reg(unwind_state_t* state, uint32_t reg, uint32_t value) {
-    ALOGV("set_reg: reg=%d, value=0x%08x", reg, value);
-    state->gregs[reg] = value;
-}
-
-static bool try_pop_registers(const memory_t* memory, unwind_state_t* state, uint32_t mask) {
-    uint32_t sp = state->gregs[R_SP];
-    bool sp_updated = false;
-    for (int i = 0; i < 16; i++) {
-        if (mask & (1 << i)) {
-            uint32_t value;
-            if (!try_get_word(memory, sp, &value)) {
-                return false;
-            }
-            if (i == R_SP) {
-                sp_updated = true;
-            }
-            set_reg(state, i, value);
-            sp += 4;
-        }
-    }
-    if (!sp_updated) {
-        set_reg(state, R_SP, sp);
-    }
-    return true;
-}
-
-/* Executes a built-in personality routine as defined in the EHABI.
- * Returns true if unwinding should continue.
- *
- * The data for the built-in personality routines consists of a sequence
- * of unwinding instructions, followed by a sequence of scope descriptors,
- * each of which has a length and offset encoded using 16-bit or 32-bit
- * values.
- *
- * We only care about the unwinding instructions.  They specify the
- * operations of an abstract machine whose purpose is to transform the
- * virtual register state (including the stack pointer) such that
- * the call frame is unwound and the PC register points to the call site.
- */
-static bool execute_personality_routine(const memory_t* memory,
-        unwind_state_t* state, byte_stream_t* stream, int pr_index) {
-    size_t size;
-    switch (pr_index) {
-    case 0: // Personality routine #0, short frame, descriptors have 16-bit scope.
-        size = 3;
-        break;
-    case 1: // Personality routine #1, long frame, descriptors have 16-bit scope.
-    case 2: { // Personality routine #2, long frame, descriptors have 32-bit scope.
-        uint8_t size_byte;
-        if (!try_next_byte(memory, stream, &size_byte)) {
-            return false;
-        }
-        size = (uint32_t)size_byte * sizeof(uint32_t) + 2;
-        break;
-    }
-    default: // Unknown personality routine.  Stop here.
-        return false;
-    }
-
-    bool pc_was_set = false;
-    while (size--) {
-        uint8_t op;
-        if (!try_next_byte(memory, stream, &op)) {
-            return false;
-        }
-        if ((op & 0xc0) == 0x00) {
-            // "vsp = vsp + (xxxxxx << 2) + 4"
-            set_reg(state, R_SP, state->gregs[R_SP] + ((op & 0x3f) << 2) + 4);
-        } else if ((op & 0xc0) == 0x40) {
-            // "vsp = vsp - (xxxxxx << 2) - 4"
-            set_reg(state, R_SP, state->gregs[R_SP] - ((op & 0x3f) << 2) - 4);
-        } else if ((op & 0xf0) == 0x80) {
-            uint8_t op2;
-            if (!(size--) || !try_next_byte(memory, stream, &op2)) {
-                return false;
-            }
-            uint32_t mask = (((uint32_t)op & 0x0f) << 12) | ((uint32_t)op2 << 4);
-            if (mask) {
-                // "Pop up to 12 integer registers under masks {r15-r12}, {r11-r4}"
-                if (!try_pop_registers(memory, state, mask)) {
-                    return false;
-                }
-                if (mask & (1 << R_PC)) {
-                    pc_was_set = true;
-                }
-            } else {
-                // "Refuse to unwind"
-                return false;
-            }
-        } else if ((op & 0xf0) == 0x90) {
-            if (op != 0x9d && op != 0x9f) {
-                // "Set vsp = r[nnnn]"
-                set_reg(state, R_SP, state->gregs[op & 0x0f]);
-            } else {
-                // "Reserved as prefix for ARM register to register moves"
-                // "Reserved as prefix for Intel Wireless MMX register to register moves"
-                return false;
-            }
-        } else if ((op & 0xf8) == 0xa0) {
-            // "Pop r4-r[4+nnn]"
-            uint32_t mask = (0x0ff0 >> (7 - (op & 0x07))) & 0x0ff0;
-            if (!try_pop_registers(memory, state, mask)) {
-                return false;
-            }
-        } else if ((op & 0xf8) == 0xa8) {
-            // "Pop r4-r[4+nnn], r14"
-            uint32_t mask = ((0x0ff0 >> (7 - (op & 0x07))) & 0x0ff0) | 0x4000;
-            if (!try_pop_registers(memory, state, mask)) {
-                return false;
-            }
-        } else if (op == 0xb0) {
-            // "Finish"
-            break;
-        } else if (op == 0xb1) {
-            uint8_t op2;
-            if (!(size--) || !try_next_byte(memory, stream, &op2)) {
-                return false;
-            }
-            if (op2 != 0x00 && (op2 & 0xf0) == 0x00) {
-                // "Pop integer registers under mask {r3, r2, r1, r0}"
-                if (!try_pop_registers(memory, state, op2)) {
-                    return false;
-                }
-            } else {
-                // "Spare"
-                return false;
-            }
-        } else if (op == 0xb2) {
-            // "vsp = vsp + 0x204 + (uleb128 << 2)"
-            uint32_t value = 0;
-            uint32_t shift = 0;
-            uint8_t op2;
-            do {
-                if (!(size--) || !try_next_byte(memory, stream, &op2)) {
-                    return false;
-                }
-                value |= (op2 & 0x7f) << shift;
-                shift += 7;
-            } while (op2 & 0x80);
-            set_reg(state, R_SP, state->gregs[R_SP] + (value << 2) + 0x204);
-        } else if (op == 0xb3) {
-            // "Pop VFP double-precision registers D[ssss]-D[ssss+cccc] saved (as if) by FSTMFDX"
-            uint8_t op2;
-            if (!(size--) || !try_next_byte(memory, stream, &op2)) {
-                return false;
-            }
-            set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op2 & 0x0f) * 8 + 12);
-        } else if ((op & 0xf8) == 0xb8) {
-            // "Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by FSTMFDX"
-            set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op & 0x07) * 8 + 12);
-        } else if ((op & 0xf8) == 0xc0) {
-            // "Intel Wireless MMX pop wR[10]-wR[10+nnn]"
-            set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op & 0x07) * 8 + 8);
-        } else if (op == 0xc6) {
-            // "Intel Wireless MMX pop wR[ssss]-wR[ssss+cccc]"
-            uint8_t op2;
-            if (!(size--) || !try_next_byte(memory, stream, &op2)) {
-                return false;
-            }
-            set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op2 & 0x0f) * 8 + 8);
-        } else if (op == 0xc7) {
-            uint8_t op2;
-            if (!(size--) || !try_next_byte(memory, stream, &op2)) {
-                return false;
-            }
-            if (op2 != 0x00 && (op2 & 0xf0) == 0x00) {
-                // "Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0}"
-                set_reg(state, R_SP, state->gregs[R_SP] + __builtin_popcount(op2) * 4);
-            } else {
-                // "Spare"
-                return false;
-            }
-        } else if (op == 0xc8) {
-            // "Pop VFP double precision registers D[16+ssss]-D[16+ssss+cccc]
-            // saved (as if) by FSTMFD"
-            uint8_t op2;
-            if (!(size--) || !try_next_byte(memory, stream, &op2)) {
-                return false;
-            }
-            set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op2 & 0x0f) * 8 + 8);
-        } else if (op == 0xc9) {
-            // "Pop VFP double precision registers D[ssss]-D[ssss+cccc] saved (as if) by FSTMFDD"
-            uint8_t op2;
-            if (!(size--) || !try_next_byte(memory, stream, &op2)) {
-                return false;
-            }
-            set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op2 & 0x0f) * 8 + 8);
-        } else if ((op == 0xf8) == 0xd0) {
-            // "Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by FSTMFDD"
-            set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op & 0x07) * 8 + 8);
-        } else {
-            // "Spare"
-            return false;
-        }
-    }
-    if (!pc_was_set) {
-        set_reg(state, R_PC, state->gregs[R_LR]);
-    }
-    return true;
-}
-
-static bool try_get_half_word(const memory_t* memory, uint32_t pc, uint16_t* out_value) {
-    uint32_t word;
-    if (try_get_word(memory, pc & ~2, &word)) {
-        *out_value = pc & 2 ? word >> 16 : word & 0xffff;
-        return true;
-    }
-    return false;
-}
-
-uintptr_t rewind_pc_arch(const memory_t* memory, uintptr_t pc) {
-    if (pc & 1) {
-        /* Thumb mode - need to check whether the bl(x) has long offset or not.
-         * Examples:
-         *
-         * arm blx in the middle of thumb:
-         * 187ae:       2300            movs    r3, #0
-         * 187b0:       f7fe ee1c       blx     173ec
-         * 187b4:       2c00            cmp     r4, #0
-         *
-         * arm bl in the middle of thumb:
-         * 187d8:       1c20            adds    r0, r4, #0
-         * 187da:       f136 fd15       bl      14f208
-         * 187de:       2800            cmp     r0, #0
-         *
-         * pure thumb:
-         * 18894:       189b            adds    r3, r3, r2
-         * 18896:       4798            blx     r3
-         * 18898:       b001            add     sp, #4
-         */
-        uint16_t prev1, prev2;
-        if (try_get_half_word(memory, pc - 5, &prev1)
-            && ((prev1 & 0xf000) == 0xf000)
-            && try_get_half_word(memory, pc - 3, &prev2)
-            && ((prev2 & 0xe000) == 0xe000)) {
-            pc -= 4; // long offset
-        } else {
-            pc -= 2;
-        }
-    } else {
-        /* ARM mode, all instructions are 32bit.  Yay! */
-        pc -= 4;
-    }
-    return pc;
-}
-
-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;
-
-    for (size_t index = 0; returned_frames < max_depth; index++) {
-        uintptr_t pc = index ? rewind_pc_arch(memory, state->gregs[R_PC])
-                : state->gregs[R_PC];
-        backtrace_frame_t* frame = add_backtrace_entry(pc,
-                backtrace, ignore_depth, max_depth, &ignored_frames, &returned_frames);
-        if (frame) {
-            frame->stack_top = state->gregs[R_SP];
-        }
-
-        uintptr_t handler = get_exception_handler(memory, map_info_list, pc);
-        if (!handler) {
-            // If there is no handler for the PC and this is the first frame,
-            // then the program may have branched to an invalid address.
-            // Try starting from the LR instead, otherwise stop unwinding.
-            if (index == 0 && state->gregs[R_LR]
-                    && state->gregs[R_LR] != state->gregs[R_PC]) {
-                set_reg(state, R_PC, state->gregs[R_LR]);
-                continue;
-            } else {
-                break;
-            }
-        }
-
-        byte_stream_t stream;
-        stream.ptr = handler;
-        uint8_t pr;
-        if (!try_next_byte(memory, &stream, &pr)) {
-            break;
-        }
-        if ((pr & 0xf0) != 0x80) {
-            // The first word is a place-relative pointer to a generic personality
-            // routine function.  We don't support invoking such functions, so stop here.
-            break;
-        }
-
-        // The first byte indicates the personality routine to execute.
-        // Following bytes provide instructions to the personality routine.
-        if (!execute_personality_routine(memory, state, &stream, pr & 0x0f)) {
-            break;
-        }
-        if (frame && state->gregs[R_SP] > frame->stack_top) {
-            frame->stack_size = state->gregs[R_SP] - frame->stack_top;
-        }
-        if (!state->gregs[R_PC]) {
-            break;
-        }
-    }
-
-    // Ran out of frames that we could unwind using handlers.
-    // Add a final entry for the LR if it looks sane and call it good.
-    if (returned_frames < max_depth
-            && state->gregs[R_LR]
-            && state->gregs[R_LR] != state->gregs[R_PC]
-            && is_executable_map(map_info_list, state->gregs[R_LR])) {
-        // We don't know where the stack for this extra frame starts so we
-        // don't return any stack information for it.
-        add_backtrace_entry(rewind_pc_arch(memory, state->gregs[R_LR]),
-                backtrace, ignore_depth, max_depth, &ignored_frames, &returned_frames);
-    }
-    return returned_frames;
-}
-
-ssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo, void* sigcontext,
-        const map_info_t* map_info_list,
-        backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
-    const ucontext_t* uc = (const ucontext_t*)sigcontext;
-
-    unwind_state_t state;
-
-    state.gregs[0] = uc->uc_mcontext.arm_r0;
-    state.gregs[1] = uc->uc_mcontext.arm_r1;
-    state.gregs[2] = uc->uc_mcontext.arm_r2;
-    state.gregs[3] = uc->uc_mcontext.arm_r3;
-    state.gregs[4] = uc->uc_mcontext.arm_r4;
-    state.gregs[5] = uc->uc_mcontext.arm_r5;
-    state.gregs[6] = uc->uc_mcontext.arm_r6;
-    state.gregs[7] = uc->uc_mcontext.arm_r7;
-    state.gregs[8] = uc->uc_mcontext.arm_r8;
-    state.gregs[9] = uc->uc_mcontext.arm_r9;
-    state.gregs[10] = uc->uc_mcontext.arm_r10;
-    state.gregs[11] = uc->uc_mcontext.arm_fp;
-    state.gregs[12] = uc->uc_mcontext.arm_ip;
-    state.gregs[13] = uc->uc_mcontext.arm_sp;
-    state.gregs[14] = uc->uc_mcontext.arm_lr;
-    state.gregs[15] = uc->uc_mcontext.arm_pc;
-
-    memory_t memory;
-    init_memory(&memory, map_info_list);
-    return unwind_backtrace_common(&memory, map_info_list, &state,
-            backtrace, ignore_depth, max_depth);
-}
-
-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) {
-    struct pt_regs regs;
-    if (ptrace(PTRACE_GETREGS, tid, 0, &regs)) {
-        return -1;
-    }
-
-    unwind_state_t state;
-    for (int i = 0; i < 16; i++) {
-        state.gregs[i] = regs.uregs[i];
-    }
-
-    memory_t memory;
-    init_memory_ptrace(&memory, tid);
-    return unwind_backtrace_common(&memory, context->map_info_list, &state,
-            backtrace, ignore_depth, max_depth);
-}
diff --git a/libcorkscrew/arch-arm/ptrace-arm.c b/libcorkscrew/arch-arm/ptrace-arm.c
deleted file mode 100644
index a50844e..0000000
--- a/libcorkscrew/arch-arm/ptrace-arm.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include "../ptrace-arch.h"
-
-#include <elf.h>
-#include <cutils/log.h>
-
-#ifndef PT_ARM_EXIDX
-#define PT_ARM_EXIDX 0x70000001
-#endif
-
-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_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_ARM_EXIDX) {
-                uint32_t elf_phdr_offset;
-                uint32_t elf_phdr_filesz;
-                if (!try_get_word_ptrace(pid, elf_phdr + offsetof(Elf32_Phdr, p_offset),
-                        &elf_phdr_offset)
-                        || !try_get_word_ptrace(pid, elf_phdr + offsetof(Elf32_Phdr, p_filesz),
-                                &elf_phdr_filesz)) {
-                    break;
-                }
-                *out_exidx_start = mi->start + elf_phdr_offset;
-                *out_exidx_size = elf_phdr_filesz / 8;
-                ALOGV("Parsed EXIDX header info for %s: start=0x%08x, size=%d", mi->name,
-                        *out_exidx_start, *out_exidx_size);
-                return;
-            }
-        }
-    }
-    *out_exidx_start = 0;
-    *out_exidx_size = 0;
-}
-
-void load_ptrace_map_info_data_arch(pid_t pid, map_info_t* mi, map_info_data_t* data) {
-    load_exidx_header(pid, mi, &data->exidx_start, &data->exidx_size);
-}
-
-void free_ptrace_map_info_data_arch(map_info_t* mi, map_info_data_t* data) {
-}
diff --git a/libcorkscrew/arch-mips/backtrace-mips.c b/libcorkscrew/arch-mips/backtrace-mips.c
deleted file mode 100644
index 57cb324..0000000
--- a/libcorkscrew/arch-mips/backtrace-mips.c
+++ /dev/null
@@ -1,936 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * Backtracing functions for mips
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#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>
-
-#if defined(__BIONIC__)
-
-#if defined(__BIONIC_HAVE_UCONTEXT_T)
-
-// Bionic offers the Linux kernel headers.
-#include <asm/sigcontext.h>
-#include <asm/ucontext.h>
-typedef struct ucontext ucontext_t;
-
-#else /* __BIONIC_HAVE_UCONTEXT_T */
-
-/* Old versions of the Android <signal.h> didn't define ucontext_t. */
-
-/* For PTRACE_GETREGS */
-typedef struct {
-    uint64_t regs[32];
-    uint64_t lo;
-    uint64_t hi;
-    uint64_t epc;
-    uint64_t badvaddr;
-    uint64_t status;
-    uint64_t cause;
-} user_regs_struct;
-
-enum {
-    REG_ZERO = 0, REG_AT, REG_V0, REG_V1,
-    REG_A0, REG_A1, REG_A2, REG_A3,
-    REG_T0, REG_T1, REG_T2, REG_T3,
-    REG_T4, REG_T5, REG_T6, REG_T7,
-    REG_S0, REG_S1, REG_S2, REG_S3,
-    REG_S4, REG_S5, REG_S6, REG_S7,
-    REG_T8, REG_T9, REG_K0, REG_K1,
-    REG_GP, REG_SP, REG_S8, REG_RA,
-};
-
-/* Machine context at the time a signal was raised. */
-typedef struct ucontext {
-    unsigned int sc_regmask;
-    unsigned int sc_status;
-    unsigned long long sc_pc;
-    unsigned long long sc_regs[32];
-    unsigned long long sc_fpregs[32];
-    unsigned int sc_acx;
-    unsigned int sc_fpc_csr;
-    unsigned int sc_fpc_eir;
-    unsigned int sc_used_math;
-    unsigned int sc_dsp;
-    unsigned long long sc_mdhi;
-    unsigned long long sc_mdlo;
-    unsigned long sc_hi1;
-    unsigned long sc_lo1;
-    unsigned long sc_hi2;
-    unsigned long sc_lo2;
-    unsigned long sc_hi3;
-    unsigned long sc_lo3;
-} ucontext_t;
-
-#endif /* __BIONIC_HAVE_UCONTEXT_T */
-#endif
-
-/* Unwind state. */
-typedef struct {
-    uint32_t reg[DWARF_REGISTERS];
-} unwind_state_t;
-
-uintptr_t rewind_pc_arch(const memory_t* memory __attribute__((unused)), uintptr_t pc) {
-    if (pc == 0)
-        return pc;
-    if ((pc & 1) == 0)
-        return pc-8;            /* jal/bal/jalr + branch delay slot */
-    return pc;
-}
-
-/* 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;
-
-    ptr += *cursor;
-
-    if (ptr < lastptr || lastptr + 3 < ptr) {
-        lastptr = (ptr >> 2) << 2;
-        if (!try_get_word(memory, lastptr, &buf)) {
-            return false;
-        }
-    }
-    *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 mips.
-        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 mips.
-        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 mips.
-        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 mips.
-        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 mips.
-        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 mips.
-        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 SP if it's not updated by dwarf rule we assume it's equal to CFA
-        // for PC if it's not updated by dwarf rule we assume it's equal to RA
-        if (reg == DWARF_SP) {
-            ALOGV("get_old_register_value: adjusting sp to CFA: 0x%x", cfa);
-            newstate->reg[reg] = cfa;
-        } else if (reg == DWARF_PC) {
-            ALOGV("get_old_register_value: adjusting PC to RA: 0x%x", newstate->reg[DWARF_RA]);
-            newstate->reg[reg] = newstate->reg[DWARF_RA];
-        } 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_SP) {
-        cfa = state->reg[DWARF_SP] + dstate->cfa_off;
-    } else if (dstate->cfa_reg == DWARF_FP) {
-        cfa = state->reg[DWARF_FP] + dstate->cfa_off;
-    } else {
-        ALOGE("update_state: unexpected CFA register: %d", dstate->cfa_reg);
-        return false;
-    }
-    ALOGV("update_state: new CFA: 0x%x", cfa);
-
-    /* Update registers. Order is important to allow RA to propagate to PC */
-    /* Getting FP. */
-    if (!get_old_register_value(memory, cfa, dstate, DWARF_FP, state, &newstate)) return false;
-    /* Getting SP. */
-    if (!get_old_register_value(memory, cfa, dstate, DWARF_SP, state, &newstate)) return false;
-    /* Getting RA. */
-    if (!get_old_register_value(memory, cfa, dstate, DWARF_RA, state, &newstate)) return false;
-    /* Getting PC. */
-    if (!get_old_register_value(memory, cfa, dstate, DWARF_PC, state, &newstate)) return false;
-
-    ALOGV("update_state: PC: 0x%x; restore PC: 0x%x", state->reg[DWARF_PC], newstate.reg[DWARF_PC]);
-    ALOGV("update_state: RA: 0x%x; restore RA: 0x%x", state->reg[DWARF_RA], newstate.reg[DWARF_RA]);
-    ALOGV("update_state: FP: 0x%x; restore FP: 0x%x", state->reg[DWARF_FP], newstate.reg[DWARF_FP]);
-    ALOGV("update_state: SP: 0x%x; restore SP: 0x%x", state->reg[DWARF_SP], newstate.reg[DWARF_SP]);
-
-    if (newstate.reg[DWARF_PC] == 0)
-        return false;
-
-    /* End backtrace if registers do not change */
-    if ((state->reg[DWARF_PC] == newstate.reg[DWARF_PC]) &&
-        (state->reg[DWARF_RA] == newstate.reg[DWARF_RA]) &&
-        (state->reg[DWARF_FP] == newstate.reg[DWARF_FP]) &&
-        (state->reg[DWARF_SP] == newstate.reg[DWARF_SP]))
-        return false;
-
-    *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_PC] >= dstate->loc) {
-        if (!execute_dwarf(memory, fde, cie_info, dstate, &c, stack, &stack_ptr)) {
-            return false;
-        }
-        ALOGV("PC: %x, LOC: %x", state->reg[DWARF_PC], dstate->loc);
-    }
-
-    return update_state(memory, state, dstate);
-}
-
-static bool heuristic_state_update(const memory_t* memory, unwind_state_t* state)
-{
-    bool found_start = false;
-    int maxcheck = 1024;
-    int32_t stack_size = 0;
-    int32_t ra_offset = 0;
-    dwarf_state_t dwarf_state;
-    dwarf_state_t* dstate = &dwarf_state;
-
-    static struct {
-        uint32_t insn;
-        uint32_t mask;
-    } frame0sig[] = {
-        {0x3c1c0000, 0xffff0000}, /* lui     gp,xxxx */
-        {0x279c0000, 0xffff0000}, /* addiu   gp,gp,xxxx */
-        {0x039fe021, 0xffffffff}, /* addu    gp,gp,ra */
-    };
-    const int nframe0sig = sizeof(frame0sig)/sizeof(frame0sig[0]);
-    int f0 = nframe0sig;
-    memset(dstate, 0, sizeof(dwarf_state_t));
-
-    /* Search code backwards looking for function prologue */
-    for (uint32_t pc = state->reg[DWARF_PC]-4; maxcheck-- > 0 && !found_start; pc -= 4) {
-        uint32_t op;
-        int32_t immediate;
-
-        if (!try_get_word(memory, pc, &op))
-            return false;
-
-        // ALOGV("@0x%08x: 0x%08x\n", pc, op);
-
-        // Check for frame 0 signature
-        if ((op & frame0sig[f0].mask) == frame0sig[f0].insn) {
-            if (f0 == 0)
-                return false;
-            f0--;
-        }
-        else {
-            f0 = nframe0sig;
-        }
-
-        switch (op & 0xffff0000) {
-        case 0x27bd0000: // addiu sp, imm
-            // looking for stack being decremented
-            immediate = (((int32_t)op) << 16) >> 16;
-            if (immediate < 0) {
-                stack_size = -immediate;
-                ALOGV("@0x%08x: found stack adjustment=%d\n", pc, stack_size);
-            }
-            break;
-        case 0x039f0000: // e021
-
-        case 0xafbf0000: // sw ra, imm(sp)
-            ra_offset = (((int32_t)op) << 16) >> 16;
-            ALOGV("@0x%08x: found ra offset=%d\n", pc, ra_offset);
-            break;
-        case 0x3c1c0000: // lui gp
-            ALOGV("@0x%08x: found function boundary", pc);
-            found_start = true;
-            break;
-        default:
-            break;
-        }
-    }
-
-    dstate->cfa_reg = DWARF_SP;
-    dstate->cfa_off = stack_size;
-
-    if (ra_offset) {
-        dstate->regs[DWARF_RA].rule = 'o';
-        dstate->regs[DWARF_RA].value = -stack_size + ra_offset;
-    }
-
-    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("PC: %x", state->reg[DWARF_PC]);
-    ALOGV("RA: %x", state->reg[DWARF_RA]);
-    ALOGV("FP: %x", state->reg[DWARF_FP]);
-    ALOGV("SP: %x", state->reg[DWARF_SP]);
-
-    for (size_t index = 0; returned_frames < max_depth; index++) {
-        uintptr_t fde = find_fde(memory, map_info_list, state->reg[DWARF_PC]);
-        backtrace_frame_t* frame = add_backtrace_entry(
-            index ? rewind_pc_arch(memory, state->reg[DWARF_PC]) : state->reg[DWARF_PC],
-            backtrace, ignore_depth, max_depth,
-            &ignored_frames, &returned_frames);
-        uint32_t stack_top = state->reg[DWARF_SP];
-
-        if (fde) {
-            /* Use FDE to update state */
-            if (!execute_fde(memory, fde, state))
-                break;
-        }
-        else {
-            /* FDE is not found, update state heuristically */
-            if (!heuristic_state_update(memory, state))
-                break;
-        }
-
-        if (frame) {
-            frame->stack_top = stack_top;
-            if (stack_top < state->reg[DWARF_SP]) {
-                frame->stack_size = state->reg[DWARF_SP] - stack_top;
-            }
-        }
-        ALOGV("Stack: 0x%x ... 0x%x - %d bytes", frame->stack_top, state->reg[DWARF_SP], frame->stack_size);
-    }
-    return returned_frames;
-}
-
-ssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo __attribute__((unused)), void* sigcontext,
-        const map_info_t* map_info_list,
-        backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
-    const ucontext_t* uc = (const ucontext_t*)sigcontext;
-
-    unwind_state_t state;
-    state.reg[DWARF_PC] = uc->sc_pc;
-    state.reg[DWARF_RA] = uc->sc_regs[REG_RA];
-    state.reg[DWARF_FP] = uc->sc_regs[REG_S8];
-    state.reg[DWARF_SP] = uc->sc_regs[REG_SP];
-
-    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.reg[DWARF_PC], state.reg[DWARF_SP], state.reg[DWARF_RA]);
-
-    memory_t memory;
-    init_memory(&memory, map_info_list);
-    return unwind_backtrace_common(&memory, map_info_list,
-                                   &state, backtrace, ignore_depth, max_depth);
-}
-
-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) {
-
-    user_regs_struct regs;
-    if (ptrace(PTRACE_GETREGS, tid, 0, &regs)) {
-        return -1;
-    }
-
-    unwind_state_t state;
-    state.reg[DWARF_PC] = regs.epc;
-    state.reg[DWARF_RA] = regs.regs[REG_RA];
-    state.reg[DWARF_FP] = regs.regs[REG_S8];
-    state.reg[DWARF_SP] = regs.regs[REG_SP];
-
-    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.reg[DWARF_PC], state.reg[DWARF_SP], state.reg[DWARF_RA]);
-
-    memory_t memory;
-    init_memory_ptrace(&memory, tid);
-    return unwind_backtrace_common(&memory, context->map_info_list,
-                                   &state, backtrace, ignore_depth, max_depth);
-}
diff --git a/libcorkscrew/arch-mips/dwarf.h b/libcorkscrew/arch-mips/dwarf.h
deleted file mode 100644
index 8504ea0..0000000
--- a/libcorkscrew/arch-mips/dwarf.h
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * 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 mips */
-typedef enum
-  {
-    UNW_MIPS_R0,
-    UNW_MIPS_R1,
-    UNW_MIPS_R2,
-    UNW_MIPS_R3,
-    UNW_MIPS_R4,
-    UNW_MIPS_R5,
-    UNW_MIPS_R6,
-    UNW_MIPS_R7,
-    UNW_MIPS_R8,
-    UNW_MIPS_R9,
-    UNW_MIPS_R10,
-    UNW_MIPS_R11,
-    UNW_MIPS_R12,
-    UNW_MIPS_R13,
-    UNW_MIPS_R14,
-    UNW_MIPS_R15,
-    UNW_MIPS_R16,
-    UNW_MIPS_R17,
-    UNW_MIPS_R18,
-    UNW_MIPS_R19,
-    UNW_MIPS_R20,
-    UNW_MIPS_R21,
-    UNW_MIPS_R22,
-    UNW_MIPS_R23,
-    UNW_MIPS_R24,
-    UNW_MIPS_R25,
-    UNW_MIPS_R26,
-    UNW_MIPS_R27,
-    UNW_MIPS_R28,
-    UNW_MIPS_R29,
-    UNW_MIPS_R30,
-    UNW_MIPS_R31,
-
-    UNW_MIPS_PC = 34,
-
-    /* FIXME: Other registers!  */
-
-    /* For MIPS, the CFA is the value of SP (r29) at the call site in the
-       previous frame.  */
-    UNW_MIPS_CFA,
-
-    UNW_TDEP_LASTREG,
-
-    UNW_TDEP_LAST_REG = UNW_MIPS_R31,
-
-    UNW_TDEP_IP = UNW_MIPS_R31,
-    UNW_TDEP_SP = UNW_MIPS_R29,
-    UNW_TDEP_EH = UNW_MIPS_R0   /* FIXME.  */
-
-  }
-mips_regnum_t;
-
-#define DWARF_REGISTERS UNW_TDEP_LASTREG
-
-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 mips
-} dwarf_state_t;
-
-/* DWARF registers we are caring about. */
-
-
-#define DWARF_SP      UNW_MIPS_R29
-#define DWARF_RA      UNW_MIPS_R31
-#define DWARF_PC      UNW_MIPS_PC
-#define DWARF_FP      UNW_MIPS_CFA /* FIXME is this correct? */
diff --git a/libcorkscrew/arch-mips/ptrace-mips.c b/libcorkscrew/arch-mips/ptrace-mips.c
deleted file mode 100644
index ba3b60a..0000000
--- a/libcorkscrew/arch-mips/ptrace-mips.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include "../ptrace-arch.h"
-
-#include <stddef.h>
-#include <elf.h>
-#include <cutils/log.h>
-
-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;
-
-
-    try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_phoff), &elf_phoff);
-    ALOGV("reading 0x%08x elf_phoff:%x",  mi->start + offsetof(Elf32_Ehdr, e_phoff), elf_phoff);
-    try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_ehsize), &elf_phentsize_ehsize);
-    ALOGV("reading 0x%08x elf_phentsize_ehsize:%x", 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);
-    ALOGV("reading 0x%08x elf_shentsize_phnum:%x", mi->start + offsetof(Elf32_Ehdr, e_phnum), 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) {
-    ALOGV("load_ptrace_map_info_data_arch");
-    load_eh_frame_hdr(pid, mi, &data->eh_frame_hdr);
-}
-
-void free_ptrace_map_info_data_arch(map_info_t* mi __attribute__((unused)),
-                                    map_info_data_t* data __attribute__((unused))) {
-    ALOGV("free_ptrace_map_info_data_arch");
-}
diff --git a/libcorkscrew/arch-x86/backtrace-x86.c b/libcorkscrew/arch-x86/backtrace-x86.c
deleted file mode 100755
index ef22821..0000000
--- a/libcorkscrew/arch-x86/backtrace-x86.c
+++ /dev/null
@@ -1,862 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Backtracing functions for x86.
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#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>
-
-#if defined(__BIONIC__)
-
-#if defined(__BIONIC_HAVE_UCONTEXT_T)
-
-// Bionic offers the Linux kernel headers.
-#include <asm/sigcontext.h>
-#include <asm/ucontext.h>
-typedef struct ucontext ucontext_t;
-
-#else /* __BIONIC_HAVE_UCONTEXT_T */
-
-/* Old versions of the Android <signal.h> didn't define ucontext_t. */
-
-typedef struct {
-  uint32_t  gregs[32];
-  void*     fpregs;
-  uint32_t  oldmask;
-  uint32_t  cr2;
-} mcontext_t;
-
-enum {
-  REG_GS = 0, REG_FS, REG_ES, REG_DS,
-  REG_EDI, REG_ESI, REG_EBP, REG_ESP,
-  REG_EBX, REG_EDX, REG_ECX, REG_EAX,
-  REG_TRAPNO, REG_ERR, REG_EIP, REG_CS,
-  REG_EFL, REG_UESP, REG_SS
-};
-
-/* Machine context at the time a signal was raised. */
-typedef struct ucontext {
-    uint32_t uc_flags;
-    struct ucontext* uc_link;
-    stack_t uc_stack;
-    mcontext_t uc_mcontext;
-    uint32_t uc_sigmask;
-} ucontext_t;
-
-#endif /* __BIONIC_HAVE_UCONTEXT_T */
-
-#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
-
-/* Unwind state. */
-typedef struct {
-    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: 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. */
-}
-
-/* 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;
-
-    ptr += *cursor;
-
-    if (ptr < lastptr || lastptr + 3 < ptr) {
-        lastptr = (ptr >> 2) << 2;
-        if (!try_get_word(memory, lastptr, &buf)) {
-            return false;
-        }
-    }
-    *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;
-}
-
-ssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo __attribute__((unused)), void* sigcontext,
-        const map_info_t* map_info_list,
-        backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
-    const ucontext_t* uc = (const ucontext_t*)sigcontext;
-
-    unwind_state_t state;
-#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);
-    return unwind_backtrace_common(&memory, map_info_list,
-            &state, backtrace, ignore_depth, max_depth);
-}
-
-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.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
deleted file mode 100755
index 962fc55..0000000
--- a/libcorkscrew/arch-x86/dwarf.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * 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
deleted file mode 100755
index 9c49b93..0000000
--- a/libcorkscrew/arch-x86/ptrace-x86.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include "../ptrace-arch.h"
-
-#include <stddef.h>
-#include <elf.h>
-#include <cutils/log.h>
-
-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)),
-                                    map_info_data_t* data __attribute__((unused))) {
-}
diff --git a/libcorkscrew/backtrace-arch.h b/libcorkscrew/backtrace-arch.h
deleted file mode 100644
index a46f80b..0000000
--- a/libcorkscrew/backtrace-arch.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* Architecture dependent functions. */
-
-#ifndef _CORKSCREW_BACKTRACE_ARCH_H
-#define _CORKSCREW_BACKTRACE_ARCH_H
-
-#include "ptrace-arch.h"
-#include <corkscrew/backtrace.h>
-
-#include <signal.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Rewind the program counter by one instruction. */
-uintptr_t rewind_pc_arch(const memory_t* memory, uintptr_t pc);
-
-ssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo, void* sigcontext,
-        const map_info_t* map_info_list,
-        backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth);
-
-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);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _CORKSCREW_BACKTRACE_ARCH_H
diff --git a/libcorkscrew/backtrace-helper.c b/libcorkscrew/backtrace-helper.c
deleted file mode 100644
index bf9d3f3..0000000
--- a/libcorkscrew/backtrace-helper.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include "backtrace-helper.h"
-
-#include <cutils/log.h>
-
-backtrace_frame_t* add_backtrace_entry(uintptr_t pc, backtrace_frame_t* backtrace,
-        size_t ignore_depth, size_t max_depth,
-        size_t* ignored_frames, size_t* returned_frames) {
-    if (*ignored_frames < ignore_depth) {
-        *ignored_frames += 1;
-        return NULL;
-    }
-    if (*returned_frames >= max_depth) {
-        return NULL;
-    }
-    backtrace_frame_t* frame = &backtrace[*returned_frames];
-    frame->absolute_pc = pc;
-    frame->stack_top = 0;
-    frame->stack_size = 0;
-    *returned_frames += 1;
-    return frame;
-}
diff --git a/libcorkscrew/backtrace-helper.h b/libcorkscrew/backtrace-helper.h
deleted file mode 100644
index 4d8a874..0000000
--- a/libcorkscrew/backtrace-helper.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* Backtrace helper functions. */
-
-#ifndef _CORKSCREW_BACKTRACE_HELPER_H
-#define _CORKSCREW_BACKTRACE_HELPER_H
-
-#include <corkscrew/backtrace.h>
-#include <sys/types.h>
-#include <stdbool.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Add a program counter to a backtrace if it will fit.
- * Returns the newly added frame, or NULL if none.
- */
-backtrace_frame_t* add_backtrace_entry(uintptr_t pc,
-        backtrace_frame_t* backtrace,
-        size_t ignore_depth, size_t max_depth,
-        size_t* ignored_frames, size_t* returned_frames);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _CORKSCREW_BACKTRACE_HELPER_H
diff --git a/libcorkscrew/backtrace.c b/libcorkscrew/backtrace.c
deleted file mode 100644
index f1dd61d..0000000
--- a/libcorkscrew/backtrace.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include "backtrace-arch.h"
-#include "backtrace-helper.h"
-#include "ptrace-arch.h"
-#include <corkscrew/map_info.h>
-#include <corkscrew/symbol_table.h>
-#include <corkscrew/ptrace.h>
-#include <corkscrew/demangle.h>
-
-#include <unistd.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <pthread.h>
-#include <unwind.h>
-#include <cutils/log.h>
-#include <cutils/atomic.h>
-
-#define __USE_GNU // For dladdr(3) in glibc.
-#include <dlfcn.h>
-
-#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.
-
-#include <unistd.h>
-#include <sys/syscall.h>
-
-static pid_t gettid() {
-  return syscall(__NR_gettid);
-}
-
-static int tgkill(int tgid, int tid, int sig) {
-  return syscall(__NR_tgkill, tgid, tid, sig);
-}
-
-#endif
-
-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;
-
-static _Unwind_Reason_Code unwind_backtrace_callback(struct _Unwind_Context* context, void* arg) {
-    backtrace_state_t* state = (backtrace_state_t*)arg;
-    uintptr_t pc = _Unwind_GetIP(context);
-    if (pc) {
-        // TODO: Get information about the stack layout from the _Unwind_Context.
-        //       This will require a new architecture-specific function to query
-        //       the appropriate registers.  Current callers of unwind_backtrace
-        //       don't need this information, so we won't bother collecting it just yet.
-        add_backtrace_entry(rewind_pc_arch(&state->memory, pc), state->backtrace,
-                state->ignore_depth, state->max_depth,
-                &state->ignored_frames, &state->returned_frames);
-    }
-    return state->returned_frames < state->max_depth ? _URC_NO_REASON : _URC_END_OF_STACK;
-}
-
-ssize_t unwind_backtrace(backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
-    ALOGV("Unwinding current thread %d.", gettid());
-
-    map_info_t* milist = acquire_my_map_info_list();
-
-    backtrace_state_t state;
-    state.backtrace = backtrace;
-    state.ignore_depth = ignore_depth;
-    state.max_depth = max_depth;
-    state.ignored_frames = 0;
-    state.returned_frames = 0;
-    init_memory(&state.memory, milist);
-
-    _Unwind_Reason_Code rc = _Unwind_Backtrace(unwind_backtrace_callback, &state);
-
-    release_my_map_info_list(milist);
-
-    if (state.returned_frames) {
-        return state.returned_frames;
-    }
-    return rc == _URC_END_OF_STACK ? 0 : -1;
-}
-
-#ifdef CORKSCREW_HAVE_ARCH
-static const int32_t STATE_DUMPING = -1;
-static const int32_t STATE_DONE = -2;
-static const int32_t STATE_CANCEL = -3;
-
-static pthread_mutex_t g_unwind_signal_mutex = PTHREAD_MUTEX_INITIALIZER;
-static volatile struct {
-    int32_t tid_state;
-    const map_info_t* map_info_list;
-    backtrace_frame_t* backtrace;
-    size_t ignore_depth;
-    size_t max_depth;
-    size_t returned_frames;
-} g_unwind_signal_state;
-
-static void unwind_backtrace_thread_signal_handler(int n __attribute__((unused)), siginfo_t* siginfo, void* sigcontext) {
-    if (!android_atomic_acquire_cas(gettid(), STATE_DUMPING, &g_unwind_signal_state.tid_state)) {
-        g_unwind_signal_state.returned_frames = unwind_backtrace_signal_arch(
-                siginfo, sigcontext,
-                g_unwind_signal_state.map_info_list,
-                g_unwind_signal_state.backtrace,
-                g_unwind_signal_state.ignore_depth,
-                g_unwind_signal_state.max_depth);
-        android_atomic_release_store(STATE_DONE, &g_unwind_signal_state.tid_state);
-    } else {
-        ALOGV("Received spurious SIGURG on thread %d that was intended for thread %d.",
-                gettid(), android_atomic_acquire_load(&g_unwind_signal_state.tid_state));
-    }
-}
-#endif
-
-ssize_t unwind_backtrace_thread(pid_t tid, backtrace_frame_t* backtrace,
-        size_t ignore_depth, size_t max_depth) {
-    if (tid == gettid()) {
-        return unwind_backtrace(backtrace, ignore_depth + 1, max_depth);
-    }
-
-    ALOGV("Unwinding thread %d from thread %d.", tid, gettid());
-
-    // 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));
-    act.sa_sigaction = unwind_backtrace_thread_signal_handler;
-    act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
-    sigemptyset(&act.sa_mask);
-
-    pthread_mutex_lock(&g_unwind_signal_mutex);
-    map_info_t* milist = acquire_my_map_info_list();
-
-    ssize_t frames = -1;
-    if (!sigaction(SIGURG, &act, &oact)) {
-        g_unwind_signal_state.map_info_list = milist;
-        g_unwind_signal_state.backtrace = backtrace;
-        g_unwind_signal_state.ignore_depth = ignore_depth;
-        g_unwind_signal_state.max_depth = max_depth;
-        g_unwind_signal_state.returned_frames = 0;
-        android_atomic_release_store(tid, &g_unwind_signal_state.tid_state);
-
-        // Signal the specific thread that we want to dump.
-        int32_t tid_state = tid;
-        if (tgkill(getpid(), tid, SIGURG)) {
-            ALOGV("Failed to send SIGURG to thread %d.", tid);
-        } else {
-            // Wait for the other thread to start dumping the stack, or time out.
-            int wait_millis = 250;
-            for (;;) {
-                tid_state = android_atomic_acquire_load(&g_unwind_signal_state.tid_state);
-                if (tid_state != tid) {
-                    break;
-                }
-                if (wait_millis--) {
-                    ALOGV("Waiting for thread %d to start dumping the stack...", tid);
-                    usleep(1000);
-                } else {
-                    ALOGV("Timed out waiting for thread %d to start dumping the stack.", tid);
-                    break;
-                }
-            }
-        }
-
-        // Try to cancel the dump if it has not started yet.
-        if (tid_state == tid) {
-            if (!android_atomic_acquire_cas(tid, STATE_CANCEL, &g_unwind_signal_state.tid_state)) {
-                ALOGV("Canceled thread %d stack dump.", tid);
-                tid_state = STATE_CANCEL;
-            } else {
-                tid_state = android_atomic_acquire_load(&g_unwind_signal_state.tid_state);
-            }
-        }
-
-        // Wait indefinitely for the dump to finish or be canceled.
-        // We cannot apply a timeout here because the other thread is accessing state that
-        // is owned by this thread, such as milist.  It should not take very
-        // long to take the dump once started.
-        while (tid_state == STATE_DUMPING) {
-            ALOGV("Waiting for thread %d to finish dumping the stack...", tid);
-            usleep(1000);
-            tid_state = android_atomic_acquire_load(&g_unwind_signal_state.tid_state);
-        }
-
-        if (tid_state == STATE_DONE) {
-            frames = g_unwind_signal_state.returned_frames;
-        }
-
-        sigaction(SIGURG, &oact, NULL);
-    }
-
-    release_my_map_info_list(milist);
-    pthread_mutex_unlock(&g_unwind_signal_mutex);
-    return frames;
-#else
-    return -1;
-#endif
-}
-
-ssize_t unwind_backtrace_ptrace(pid_t tid, const ptrace_context_t* context,
-        backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
-#ifdef CORKSCREW_HAVE_ARCH
-    return unwind_backtrace_ptrace_arch(tid, context, backtrace, ignore_depth, max_depth);
-#else
-    return -1;
-#endif
-}
-
-static void init_backtrace_symbol(backtrace_symbol_t* symbol, uintptr_t pc) {
-    symbol->relative_pc = pc;
-    symbol->relative_symbol_addr = 0;
-    symbol->map_name = NULL;
-    symbol->symbol_name = NULL;
-    symbol->demangled_name = NULL;
-}
-
-void get_backtrace_symbols(const backtrace_frame_t* backtrace, size_t frames,
-        backtrace_symbol_t* backtrace_symbols) {
-    map_info_t* milist = acquire_my_map_info_list();
-    for (size_t i = 0; i < frames; i++) {
-        const backtrace_frame_t* frame = &backtrace[i];
-        backtrace_symbol_t* symbol = &backtrace_symbols[i];
-        init_backtrace_symbol(symbol, frame->absolute_pc);
-
-        const map_info_t* mi = find_map_info(milist, frame->absolute_pc);
-        if (mi) {
-            symbol->relative_pc = frame->absolute_pc - mi->start;
-            if (mi->name[0]) {
-                symbol->map_name = strdup(mi->name);
-            }
-            Dl_info info;
-            if (dladdr((const void*)frame->absolute_pc, &info) && info.dli_sname) {
-                symbol->relative_symbol_addr = (uintptr_t)info.dli_saddr
-                        - (uintptr_t)info.dli_fbase;
-                symbol->symbol_name = strdup(info.dli_sname);
-                symbol->demangled_name = demangle_symbol_name(symbol->symbol_name);
-            }
-        }
-    }
-    release_my_map_info_list(milist);
-}
-
-void get_backtrace_symbols_ptrace(const ptrace_context_t* context,
-        const backtrace_frame_t* backtrace, size_t frames,
-        backtrace_symbol_t* backtrace_symbols) {
-    for (size_t i = 0; i < frames; i++) {
-        const backtrace_frame_t* frame = &backtrace[i];
-        backtrace_symbol_t* symbol = &backtrace_symbols[i];
-        init_backtrace_symbol(symbol, frame->absolute_pc);
-
-        const map_info_t* mi;
-        const symbol_t* s;
-        find_symbol_ptrace(context, frame->absolute_pc, &mi, &s);
-        if (mi) {
-            symbol->relative_pc = frame->absolute_pc - mi->start;
-            if (mi->name[0]) {
-                symbol->map_name = strdup(mi->name);
-            }
-        }
-        if (s) {
-            symbol->relative_symbol_addr = s->start;
-            symbol->symbol_name = strdup(s->name);
-            symbol->demangled_name = demangle_symbol_name(symbol->symbol_name);
-        }
-    }
-}
-
-void free_backtrace_symbols(backtrace_symbol_t* backtrace_symbols, size_t frames) {
-    for (size_t i = 0; i < frames; i++) {
-        backtrace_symbol_t* symbol = &backtrace_symbols[i];
-        free(symbol->map_name);
-        free(symbol->symbol_name);
-        free(symbol->demangled_name);
-        init_backtrace_symbol(symbol, 0);
-    }
-}
-
-void format_backtrace_line(unsigned frameNumber, const backtrace_frame_t* frame __attribute__((unused)),
-        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;
-    int fieldWidth = (bufferSize - 80) / 2;
-    if (symbolName) {
-        uint32_t pc_offset = symbol->relative_pc - symbol->relative_symbol_addr;
-        if (pc_offset) {
-            snprintf(buffer, bufferSize, "#%02u  pc %08x  %.*s (%.*s+%u)",
-                    frameNumber, (unsigned int) symbol->relative_pc,
-                    fieldWidth, mapName, fieldWidth, symbolName, pc_offset);
-        } else {
-            snprintf(buffer, bufferSize, "#%02u  pc %08x  %.*s (%.*s)",
-                    frameNumber, (unsigned int) symbol->relative_pc,
-                    fieldWidth, mapName, fieldWidth, symbolName);
-        }
-    } else {
-        snprintf(buffer, bufferSize, "#%02u  pc %08x  %.*s",
-                frameNumber, (unsigned int) symbol->relative_pc,
-                fieldWidth, mapName);
-    }
-}
diff --git a/libcorkscrew/demangle.c b/libcorkscrew/demangle.c
deleted file mode 100644
index 30ab1b0..0000000
--- a/libcorkscrew/demangle.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include <corkscrew/demangle.h>
-
-#include <cutils/log.h>
-
-extern char *__cxa_demangle (const char *mangled, char *buf, size_t *len,
-                             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
deleted file mode 100644
index 93dffbf..0000000
--- a/libcorkscrew/map_info.c
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include <corkscrew/map_info.h>
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-#include <pthread.h>
-#include <unistd.h>
-#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
-static map_info_t* parse_maps_line(const char* line)
-{
-    unsigned long int start;
-    unsigned long int end;
-    char permissions[5];
-    int name_pos;
-    if (sscanf(line, "%lx-%lx %4s %*x %*x:%*x %*d%n", &start, &end,
-            permissions, &name_pos) != 3) {
-        return NULL;
-    }
-
-    while (isspace(line[name_pos])) {
-        name_pos += 1;
-    }
-    const char* name = line + name_pos;
-    size_t name_len = strlen(name);
-    if (name_len && name[name_len - 1] == '\n') {
-        name_len -= 1;
-    }
-
-    map_info_t* mi = calloc(1, sizeof(map_info_t) + name_len + 1);
-    if (mi) {
-        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_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 tid) {
-    char path[PATH_MAX];
-    char line[1024];
-    FILE* fp;
-    map_info_t* milist = NULL;
-
-    snprintf(path, PATH_MAX, "/proc/%d/maps", tid);
-    fp = fopen(path, "r");
-    if (fp) {
-        while(fgets(line, sizeof(line), fp)) {
-            map_info_t* mi = parse_maps_line(line);
-            if (mi) {
-                mi->next = milist;
-                milist = mi;
-            }
-        }
-        fclose(fp);
-    }
-    return milist;
-}
-
-#endif
-
-void free_map_info_list(map_info_t* milist) {
-    while (milist) {
-        map_info_t* next = milist->next;
-        free(milist);
-        milist = next;
-    }
-}
-
-const map_info_t* find_map_info(const map_info_t* milist, uintptr_t addr) {
-    const map_info_t* mi = milist;
-    while (mi && !(addr >= mi->start && addr < mi->end)) {
-        mi = mi->next;
-    }
-    return mi;
-}
-
-bool is_readable_map(const map_info_t* milist, uintptr_t addr) {
-    const map_info_t* mi = find_map_info(milist, addr);
-    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;
-}
-
-static pthread_mutex_t g_my_map_info_list_mutex = PTHREAD_MUTEX_INITIALIZER;
-static map_info_t* g_my_map_info_list = NULL;
-
-static const int64_t MAX_CACHE_AGE = 5 * 1000 * 1000000LL;
-
-typedef struct {
-    uint32_t refs;
-    int64_t timestamp;
-} my_map_info_data_t;
-
-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) {
-    if (!--data->refs) {
-        ALOGV("Freed my_map_info_list %p.", milist);
-        free(data);
-        free_map_info_list(milist);
-    }
-}
-
-map_info_t* acquire_my_map_info_list() {
-    pthread_mutex_lock(&g_my_map_info_list_mutex);
-
-    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) {
-            ALOGV("Invalidated my_map_info_list %p, age=%lld.", g_my_map_info_list, age);
-            dec_ref(g_my_map_info_list, data);
-            g_my_map_info_list = NULL;
-        } else {
-            ALOGV("Reusing my_map_info_list %p, age=%lld.", g_my_map_info_list, age);
-        }
-    }
-
-    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 != NULL) {
-            ALOGV("Loaded my_map_info_list %p.", g_my_map_info_list);
-            g_my_map_info_list->data = data;
-            data->refs = 1;
-            data->timestamp = time;
-        } else {
-            free(data);
-        }
-    }
-
-    map_info_t* milist = g_my_map_info_list;
-    if (milist) {
-        my_map_info_data_t* data = (my_map_info_data_t*)g_my_map_info_list->data;
-        data->refs += 1;
-    }
-
-    pthread_mutex_unlock(&g_my_map_info_list_mutex);
-    return milist;
-}
-
-void release_my_map_info_list(map_info_t* milist) {
-    if (milist) {
-        pthread_mutex_lock(&g_my_map_info_list_mutex);
-
-        my_map_info_data_t* data = (my_map_info_data_t*)milist->data;
-        dec_ref(milist, data);
-
-        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
deleted file mode 100755
index 0bcff63..0000000
--- a/libcorkscrew/ptrace-arch.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* Architecture dependent functions. */
-
-#ifndef _CORKSCREW_PTRACE_ARCH_H
-#define _CORKSCREW_PTRACE_ARCH_H
-
-#include <corkscrew/ptrace.h>
-#include <corkscrew/map_info.h>
-#include <corkscrew/symbol_table.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Custom extra data we stuff into map_info_t structures as part
- * of our ptrace_context_t. */
-typedef struct {
-#ifdef __arm__
-    uintptr_t exidx_start;
-    size_t exidx_size;
-#elif __mips__
-    uintptr_t eh_frame_hdr;
-#elif __i386__
-    uintptr_t eh_frame_hdr;
-#endif
-    symbol_table_t* symbol_table;
-} map_info_data_t;
-
-void load_ptrace_map_info_data_arch(pid_t pid, map_info_t* mi, map_info_data_t* data);
-void free_ptrace_map_info_data_arch(map_info_t* mi, map_info_data_t* data);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _CORKSCREW_PTRACE_ARCH_H
diff --git a/libcorkscrew/ptrace.c b/libcorkscrew/ptrace.c
deleted file mode 100644
index be58f7f..0000000
--- a/libcorkscrew/ptrace.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include "ptrace-arch.h"
-#include <corkscrew/ptrace.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <sys/ptrace.h>
-#include <cutils/log.h>
-
-static const uint32_t ELF_MAGIC = 0x464C457f; // "ELF\0177"
-
-#ifndef PAGE_SIZE
-#define PAGE_SIZE 4096
-#endif
-
-#ifndef PAGE_MASK
-#define PAGE_MASK (~(PAGE_SIZE - 1))
-#endif
-
-void init_memory(memory_t* memory, const map_info_t* map_info_list) {
-    memory->tid = -1;
-    memory->map_info_list = map_info_list;
-}
-
-void init_memory_ptrace(memory_t* memory, pid_t tid) {
-    memory->tid = tid;
-    memory->map_info_list = NULL;
-}
-
-bool try_get_word(const memory_t* memory, uintptr_t ptr, uint32_t* out_value) {
-    ALOGV("try_get_word: reading word at %p", (void*) ptr);
-    if (ptr & 3) {
-        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 %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;
-        *out_value = ptrace(PTRACE_PEEKTEXT, memory->tid, (void*)ptr, NULL);
-        if (*out_value == 0xffffffffL && errno) {
-            ALOGV("try_get_word: invalid pointer 0x%08x reading from tid %d, "
-                    "ptrace() errno=%d", ptr, memory->tid, errno);
-            return false;
-        }
-        return true;
-#endif
-    }
-}
-
-bool try_get_word_ptrace(pid_t tid, uintptr_t ptr, uint32_t* out_value) {
-    memory_t memory;
-    init_memory_ptrace(&memory, tid);
-    return try_get_word(&memory, ptr, out_value);
-}
-
-static void load_ptrace_map_info_data(pid_t pid, map_info_t* mi) {
-    if (mi->is_executable && mi->is_readable) {
-        uint32_t elf_magic;
-        if (try_get_word_ptrace(pid, mi->start, &elf_magic) && elf_magic == ELF_MAGIC) {
-            map_info_data_t* data = (map_info_data_t*)calloc(1, sizeof(map_info_data_t));
-            if (data) {
-                mi->data = data;
-                if (mi->name[0]) {
-                    data->symbol_table = load_symbol_table(mi->name);
-                }
-#ifdef CORKSCREW_HAVE_ARCH
-                load_ptrace_map_info_data_arch(pid, mi, data);
-#endif
-            }
-        }
-    }
-}
-
-ptrace_context_t* load_ptrace_context(pid_t pid) {
-    ptrace_context_t* context =
-            (ptrace_context_t*)calloc(1, sizeof(ptrace_context_t));
-    if (context) {
-        context->map_info_list = load_map_info_list(pid);
-        for (map_info_t* mi = context->map_info_list; mi; mi = mi->next) {
-            load_ptrace_map_info_data(pid, mi);
-        }
-    }
-    return context;
-}
-
-static void free_ptrace_map_info_data(map_info_t* mi) {
-    map_info_data_t* data = (map_info_data_t*)mi->data;
-    if (data) {
-        if (data->symbol_table) {
-            free_symbol_table(data->symbol_table);
-        }
-#ifdef CORKSCREW_HAVE_ARCH
-        free_ptrace_map_info_data_arch(mi, data);
-#endif
-        free(data);
-        mi->data = NULL;
-    }
-}
-
-void free_ptrace_context(ptrace_context_t* context) {
-    for (map_info_t* mi = context->map_info_list; mi; mi = mi->next) {
-        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,
-        uintptr_t addr, const map_info_t** out_map_info, const symbol_t** out_symbol) {
-    const map_info_t* mi = find_map_info(context->map_info_list, addr);
-    const symbol_t* symbol = NULL;
-    if (mi) {
-        const map_info_data_t* data = (const map_info_data_t*)mi->data;
-        if (data && data->symbol_table) {
-            symbol = find_symbol(data->symbol_table, addr - mi->start);
-        }
-    }
-    *out_map_info = mi;
-    *out_symbol = symbol;
-}
diff --git a/libcorkscrew/symbol_table.c b/libcorkscrew/symbol_table.c
deleted file mode 100644
index 982ccc8..0000000
--- a/libcorkscrew/symbol_table.c
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include <corkscrew/symbol_table.h>
-
-#include <stdbool.h>
-#include <stdlib.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 &&
-            e->e_ident[EI_MAG2] == ELFMAG2 &&
-            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;
-    const symbol_t* bsym = (const symbol_t*)b;
-    if (asym->start > bsym->start) return 1;
-    if (asym->start < bsym->start) return -1;
-    return 0;
-}
-
-// Compare function for bsearch
-static int bcompar(const void *key, const void *element) {
-    uintptr_t addr = *(const uintptr_t*)key;
-    const symbol_t* symbol = (const symbol_t*)element;
-    if (addr < symbol->start) return -1;
-    if (addr >= symbol->end) return 1;
-    return 0;
-}
-
-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);
-    if (fd < 0) {
-        goto out;
-    }
-
-    struct stat sb;
-    if (fstat(fd, &sb)) {
-        goto out_close;
-    }
-
-    size_t length = sb.st_size;
-    char* base = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
-    if (base == MAP_FAILED) {
-        goto out_close;
-    }
-
-    // Parse the file header
-    Elf32_Ehdr *hdr = (Elf32_Ehdr*)base;
-    if (!is_elf(hdr)) {
-        goto out_close;
-    }
-    Elf32_Shdr *shdr = (Elf32_Shdr*)(base + hdr->e_shoff);
-
-    // Search for the dynamic symbols section
-    int sym_idx = -1;
-    int dynsym_idx = -1;
-    for (Elf32_Half i = 0; i < hdr->e_shnum; i++) {
-        if (shdr[i].sh_type == SHT_SYMTAB) {
-            sym_idx = i;
-        }
-        if (shdr[i].sh_type == SHT_DYNSYM) {
-            dynsym_idx = i;
-        }
-    }
-    if (dynsym_idx == -1 && sym_idx == -1) {
-        goto out_unmap;
-    }
-
-    table = malloc(sizeof(symbol_table_t));
-    if(!table) {
-        goto out_unmap;
-    }
-    table->num_symbols = 0;
-
-    Elf32_Sym *dynsyms = NULL;
-    int dynnumsyms = 0;
-    char *dynstr = NULL;
-    if (dynsym_idx != -1) {
-        dynsyms = (Elf32_Sym*)(base + shdr[dynsym_idx].sh_offset);
-        dynnumsyms = shdr[dynsym_idx].sh_size / shdr[dynsym_idx].sh_entsize;
-        int dynstr_idx = shdr[dynsym_idx].sh_link;
-        dynstr = base + shdr[dynstr_idx].sh_offset;
-    }
-
-    Elf32_Sym *syms = NULL;
-    int numsyms = 0;
-    char *str = NULL;
-    if (sym_idx != -1) {
-        syms = (Elf32_Sym*)(base + shdr[sym_idx].sh_offset);
-        numsyms = shdr[sym_idx].sh_size / shdr[sym_idx].sh_entsize;
-        int str_idx = shdr[sym_idx].sh_link;
-        str = base + shdr[str_idx].sh_offset;
-    }
-
-    int dynsymbol_count = 0;
-    if (dynsym_idx != -1) {
-        // Iterate through the dynamic symbol table, and count how many symbols
-        // are actually defined
-        for (int i = 0; i < dynnumsyms; i++) {
-            if (dynsyms[i].st_shndx != SHN_UNDEF) {
-                dynsymbol_count++;
-            }
-        }
-    }
-
-    size_t symbol_count = 0;
-    if (sym_idx != -1) {
-        // Iterate through the symbol table, and count how many symbols
-        // are actually defined
-        for (int i = 0; i < numsyms; i++) {
-            if (syms[i].st_shndx != SHN_UNDEF
-                    && str[syms[i].st_name]
-                    && syms[i].st_value
-                    && syms[i].st_size) {
-                symbol_count++;
-            }
-        }
-    }
-
-    // Now, create an entry in our symbol table structure for each symbol...
-    table->num_symbols += symbol_count + dynsymbol_count;
-    table->symbols = malloc(table->num_symbols * sizeof(symbol_t));
-    if (!table->symbols) {
-        free(table);
-        table = NULL;
-        goto out_unmap;
-    }
-
-    size_t symbol_index = 0;
-    if (dynsym_idx != -1) {
-        // ...and populate them
-        for (int i = 0; i < dynnumsyms; i++) {
-            if (dynsyms[i].st_shndx != SHN_UNDEF) {
-                table->symbols[symbol_index].name = strdup(dynstr + dynsyms[i].st_name);
-                table->symbols[symbol_index].start = dynsyms[i].st_value;
-                table->symbols[symbol_index].end = dynsyms[i].st_value + dynsyms[i].st_size;
-                ALOGV("  [%d] '%s' 0x%08x-0x%08x (DYNAMIC)",
-                        symbol_index, table->symbols[symbol_index].name,
-                        table->symbols[symbol_index].start, table->symbols[symbol_index].end);
-                symbol_index += 1;
-            }
-        }
-    }
-
-    if (sym_idx != -1) {
-        // ...and populate them
-        for (int i = 0; i < numsyms; i++) {
-            if (syms[i].st_shndx != SHN_UNDEF
-                    && str[syms[i].st_name]
-                    && syms[i].st_value
-                    && syms[i].st_size) {
-                table->symbols[symbol_index].name = strdup(str + syms[i].st_name);
-                table->symbols[symbol_index].start = syms[i].st_value;
-                table->symbols[symbol_index].end = syms[i].st_value + syms[i].st_size;
-                ALOGV("  [%d] '%s' 0x%08x-0x%08x",
-                        symbol_index, table->symbols[symbol_index].name,
-                        table->symbols[symbol_index].start, table->symbols[symbol_index].end);
-                symbol_index += 1;
-            }
-        }
-    }
-
-    // Sort the symbol table entries, so they can be bsearched later
-    qsort(table->symbols, table->num_symbols, sizeof(symbol_t), qcompar);
-
-out_unmap:
-    munmap(base, length);
-
-out_close:
-    close(fd);
-#endif
-
-out:
-    return table;
-}
-
-void free_symbol_table(symbol_table_t* table) {
-    if (table) {
-        for (size_t i = 0; i < table->num_symbols; i++) {
-            free(table->symbols[i].name);
-        }
-        free(table->symbols);
-        free(table);
-    }
-}
-
-const symbol_t* find_symbol(const symbol_table_t* table, uintptr_t addr) {
-    if (!table) return NULL;
-    return (const symbol_t*)bsearch(&addr, table->symbols, table->num_symbols,
-            sizeof(symbol_t), bcompar);
-}
diff --git a/libcorkscrew/test.cpp b/libcorkscrew/test.cpp
deleted file mode 100644
index 22dfa7d..0000000
--- a/libcorkscrew/test.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-#include <corkscrew/backtrace.h>
-#include <corkscrew/symbol_table.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-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);
-
-  for (size_t i = 0; i < (size_t) frame_count; ++i) {
-    char line[MAX_BACKTRACE_LINE_LENGTH];
-    format_backtrace_line(i, &frames[i], &backtrace_symbols[i],
-                          line, MAX_BACKTRACE_LINE_LENGTH);
-    if (backtrace_symbols[i].symbol_name != NULL) {
-      // get_backtrace_symbols found the symbol's name with dladdr(3).
-      fprintf(stderr, "  %s\n", line);
-    } else {
-      // We don't have a symbol. Maybe this is a static symbol, and
-      // we can look it up?
-      symbol_table_t* symbols = NULL;
-      if (backtrace_symbols[i].map_name != NULL) {
-        symbols = load_symbol_table(backtrace_symbols[i].map_name);
-      }
-      const symbol_t* symbol = NULL;
-      if (symbols != NULL) {
-        symbol = find_symbol(symbols, frames[i].absolute_pc);
-      }
-      if (symbol != NULL) {
-        int offset = frames[i].absolute_pc - symbol->start;
-        fprintf(stderr, "  %s (%s%+d)\n", line, symbol->name, offset);
-      } else {
-        fprintf(stderr, "  %s (\?\?\?)\n", line);
-      }
-      free_symbol_table(symbols);
-    }
-  }
-
-  free_backtrace_symbols(backtrace_symbols, frame_count);
-  free(backtrace_symbols);
-  free(frames);
-  return frame_count;
-}
-
-struct C {
-  int g(int i);
-};
-
-__attribute__ ((noinline)) int C::g(int i) {
-  if (i == 0) {
-    return do_backtrace(0.1);
-  }
-  return g(i - 1);
-}
-
-extern "C" __attribute__ ((noinline)) int f() {
-  C c;
-  return c.g(5);
-}
-
-int main() {
-  flush_my_map_info_list();
-  f();
-
-  flush_my_map_info_list();
-  f();
-
-  return 0;
-}
diff --git a/libctest/Android.mk b/libctest/Android.mk
deleted file mode 100644
index 815fabb..0000000
--- a/libctest/Android.mk
+++ /dev/null
@@ -1,7 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libctest
-LOCAL_SRC_FILES := ctest.c
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/libctest/NOTICE b/libctest/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/libctest/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
-   Copyright (c) 2005-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.
-
-   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.
-
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
diff --git a/libctest/ctest.c b/libctest/ctest.c
deleted file mode 100644
index ee6331f..0000000
--- a/libctest/ctest.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 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.
- * 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 <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <ctest/ctest.h>
-
-#define MAX_TESTS 255
-
-/** Semi-random number used to identify assertion errors. */
-#define ASSERTION_ERROR 42
-    
-typedef void TestCase();
-
-/** A suite of tests. */
-typedef struct {
-    int size;
-    const char* testNames[MAX_TESTS];
-    TestCase* tests[MAX_TESTS];
-    int currentTest;
-    FILE* out;
-} TestSuite;
-
-/** Gets the test suite. Creates it if necessary. */
-static TestSuite* getTestSuite() {
-    static TestSuite* suite = NULL;
-    
-    if (suite != NULL) {
-        return suite;
-    }
-    
-    suite = calloc(1, sizeof(TestSuite));
-    assert(suite != NULL);
-    
-    suite->out = tmpfile();
-    assert(suite->out != NULL);
-    
-    return suite;
-}
-
-void addNamedTest(const char* name, TestCase* test) {
-    TestSuite* testSuite = getTestSuite();
-    assert(testSuite->size <= MAX_TESTS);
-    
-    int index = testSuite->size;
-    testSuite->testNames[index] = name;
-    testSuite->tests[index] = test;
-    
-    testSuite->size++;
-}
-
-/** Prints failures to stderr. */
-static void printFailures(int failures) {
-    TestSuite* suite = getTestSuite();
-
-    fprintf(stderr, "FAILURE! %d of %d tests failed. Failures:\n", 
-            failures, suite->size);
-
-    // Copy test output to stdout.
-    rewind(suite->out);
-    char buffer[512];
-    size_t read;
-    while ((read = fread(buffer, sizeof(char), 512, suite->out)) > 0) {
-        // TODO: Make sure we actually wrote 'read' bytes.
-        fwrite(buffer, sizeof(char), read, stderr);
-    }
-}
-
-/** Runs a single test case. */
-static int runCurrentTest() {
-    TestSuite* suite = getTestSuite();
-    
-    pid_t pid = fork();
-    if (pid == 0) {
-        // Child process. Runs test case.
-        suite->tests[suite->currentTest]();
-        
-        // Exit successfully.
-        exit(0);
-    } else if (pid < 0) {
-        fprintf(stderr, "Fork failed.");
-        exit(1); 
-    } else {
-        // Parent process. Wait for child.
-        int status;
-        waitpid(pid, &status, 0);
-        
-        if (!WIFEXITED(status)) {
-            return -1;
-        }
-        
-        return WEXITSTATUS(status);
-    }
-}
-
-void runTests() {
-    TestSuite* suite = getTestSuite();
-   
-    int failures = 0;
-    for (suite->currentTest = 0; suite->currentTest < suite->size; 
-            suite->currentTest++) {
-        // Flush stdout before forking.
-        fflush(stdout);
-        
-        int result = runCurrentTest();
-       
-        if (result != 0) {
-            printf("X");
-            
-            failures++;
-
-            // Handle errors other than assertions.
-            if (result != ASSERTION_ERROR) {
-                // TODO: Report file name.
-                fprintf(suite->out, "Process failed: [%s] status: %d\n",
-                        suite->testNames[suite->currentTest], result);
-                fflush(suite->out);
-            }
-        } else {
-            printf(".");
-        }
-    }
-
-    printf("\n");
-    
-    if (failures > 0) {
-        printFailures(failures);
-    } else {
-        printf("SUCCESS! %d tests ran successfully.\n", suite->size);
-    }
-}
-
-void assertTrueWithSource(int value, const char* file, int line, char* message) {
-    if (!value) {
-        TestSuite* suite = getTestSuite();
-
-        fprintf(suite->out, "Assertion failed: [%s:%d] %s: %s\n", file, line, 
-                suite->testNames[suite->currentTest], message);
-        fflush(suite->out);
-        
-        // Exit the process for this test case.
-        exit(ASSERTION_ERROR);
-    }
-}
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 93bccb0..933a77b 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -27,13 +27,6 @@
 	hashmap.c \
 	atomic.c.arm \
 	native_handle.c \
-	socket_inaddr_any_server.c \
-	socket_local_client.c \
-	socket_local_server.c \
-	socket_loopback_client.c \
-	socket_loopback_server.c \
-	socket_network_client.c \
-	sockets.c \
 	config_utils.c \
 	cpu_info.c \
 	load_file.c \
@@ -47,9 +40,6 @@
 	iosched_policy.c \
 	str_parms.c \
 
-commonHostSources := \
-        ashmem-host.c
-
 # some files must not be compiled when building against Mingw
 # they correspond to features not used by our host development tools
 # which are also hard or even impossible to port to native Win32
@@ -67,7 +57,18 @@
 ifneq ($(WINDOWS_HOST_ONLY),1)
     commonSources += \
         fs.c \
-        multiuser.c
+        multiuser.c \
+        socket_inaddr_any_server.c \
+        socket_local_client.c \
+        socket_local_server.c \
+        socket_loopback_client.c \
+        socket_loopback_server.c \
+        socket_network_client.c \
+        sockets.c \
+
+    commonHostSources += \
+        ashmem-host.c
+
 endif
 
 
@@ -75,9 +76,13 @@
 # ========================================================
 LOCAL_MODULE := libcutils
 LOCAL_SRC_FILES := $(commonSources) $(commonHostSources) dlmalloc_stubs.c
-LOCAL_LDLIBS := -lpthread
 LOCAL_STATIC_LIBRARIES := liblog
 LOCAL_CFLAGS += $(hostSmpFlag)
+ifneq ($(HOST_OS),windows)
+LOCAL_CFLAGS += -Werror
+endif
+LOCAL_MULTILIB := both
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 
@@ -86,11 +91,28 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := lib64cutils
 LOCAL_SRC_FILES := $(commonSources) $(commonHostSources) dlmalloc_stubs.c
-LOCAL_LDLIBS := -lpthread
 LOCAL_STATIC_LIBRARIES := lib64log
 LOCAL_CFLAGS += $(hostSmpFlag) -m64
+ifneq ($(HOST_OS),windows)
+LOCAL_CFLAGS += -Werror
+endif
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_HOST_STATIC_LIBRARY)
 
+# Tests for host
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := tst_str_parms
+LOCAL_CFLAGS += -DTEST_STR_PARMS
+ifneq ($(HOST_OS),windows)
+LOCAL_CFLAGS += -Werror
+endif
+LOCAL_SRC_FILES := str_parms.c hashmap.c memory.c
+LOCAL_STATIC_LIBRARIES := liblog
+LOCAL_MODULE_TAGS := optional
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+include $(BUILD_HOST_EXECUTABLE)
+
 
 # Shared and static library for target
 # ========================================================
@@ -102,30 +124,40 @@
         ashmem-dev.c \
         debugger.c \
         klog.c \
+        memory.c \
         partition_utils.c \
         properties.c \
         qtaguid.c \
         trace.c \
-        uevent.c
+        uevent.c \
 
-ifeq ($(TARGET_ARCH),arm)
-    LOCAL_SRC_FILES += arch-arm/memset32.S
-else  # !arm
-    ifeq ($(TARGET_ARCH),x86)
-        LOCAL_CFLAGS += -DHAVE_MEMSET16 -DHAVE_MEMSET32
-        LOCAL_SRC_FILES += arch-x86/android_memset16.S arch-x86/android_memset32.S memory.c
-    else # !x86
-        ifeq ($(TARGET_ARCH),mips)
-            LOCAL_SRC_FILES += arch-mips/android_memset.c
-        else # !mips
-            LOCAL_SRC_FILES += memory.c
-        endif # !mips
-    endif # !x86
-endif # !arm
+LOCAL_SRC_FILES_arm += \
+        arch-arm/memset32.S \
+
+LOCAL_SRC_FILES_arm64 += \
+        arch-arm64/android_memset.S \
+
+LOCAL_SRC_FILES_mips += \
+        arch-mips/android_memset.c \
+
+LOCAL_SRC_FILES_x86 += \
+        arch-x86/android_memset16.S \
+        arch-x86/android_memset32.S \
+
+LOCAL_SRC_FILES_x86_64 += \
+        arch-x86_64/android_memset16_SSE2-atom.S \
+        arch-x86_64/android_memset32_SSE2-atom.S \
+
+LOCAL_CFLAGS_arm += -DHAVE_MEMSET16 -DHAVE_MEMSET32
+LOCAL_CFLAGS_arm64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
+LOCAL_CFLAGS_mips += -DHAVE_MEMSET16 -DHAVE_MEMSET32
+LOCAL_CFLAGS_x86 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
+LOCAL_CFLAGS_x86_64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
 
 LOCAL_C_INCLUDES := $(libcutils_c_includes)
 LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_CFLAGS += $(targetSmpFlag)
+LOCAL_CFLAGS += $(targetSmpFlag) -Werror
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -134,16 +166,18 @@
 # liblog symbols present in libcutils.
 LOCAL_WHOLE_STATIC_LIBRARIES := libcutils liblog
 LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_CFLAGS += $(targetSmpFlag)
+LOCAL_CFLAGS += $(targetSmpFlag) -Werror
 LOCAL_C_INCLUDES := $(libcutils_c_includes)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_SHARED_LIBRARY)
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := tst_str_parms
-LOCAL_CFLAGS += -DTEST_STR_PARMS
+LOCAL_CFLAGS += -DTEST_STR_PARMS -Werror
 LOCAL_SRC_FILES := str_parms.c hashmap.c memory.c
 LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_MODULE_TAGS := optional
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_EXECUTABLE)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libcutils/android_reboot.c b/libcutils/android_reboot.c
index b7895fa..5d98295 100644
--- a/libcutils/android_reboot.c
+++ b/libcutils/android_reboot.c
@@ -57,7 +57,7 @@
         mount_dir[255] = 0;
         mount_type[255] = 0;
         mount_opts[255] = 0;
-        if ((match == 6) && !strncmp(mount_dev, "/dev/block", 10) && strstr(mount_opts, "rw")) {
+        if ((match == 6) && !strncmp(mount_dev, "/dev/block", 10) && strstr(mount_opts, "rw,")) {
             found_rw_fs = 1;
             break;
         }
diff --git a/libcutils/arch-arm/memset32.S b/libcutils/arch-arm/memset32.S
index 4697265..6efab9f 100644
--- a/libcutils/arch-arm/memset32.S
+++ b/libcutils/arch-arm/memset32.S
@@ -51,8 +51,10 @@
 
 android_memset32:
         .fnstart
-        .save       {lr}
+        .cfi_startproc
         str         lr, [sp, #-4]!
+        .cfi_def_cfa_offset 4
+        .cfi_rel_offset lr, 0
 
         /* align the destination to a cache-line */
         mov         r12, r1
@@ -89,5 +91,8 @@
         strmih      lr, [r0], #2
 
         ldr         lr, [sp], #4
+        .cfi_def_cfa_offset 0
+        .cfi_restore lr
         bx          lr
+        .cfi_endproc
         .fnend
diff --git a/libcutils/arch-arm64/android_memset.S b/libcutils/arch-arm64/android_memset.S
new file mode 100644
index 0000000..9a83a68
--- /dev/null
+++ b/libcutils/arch-arm64/android_memset.S
@@ -0,0 +1,211 @@
+/* Copyright (c) 2012, Linaro Limited
+   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 the Linaro 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
+   HOLDER 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.
+*/
+
+/* Assumptions:
+ *
+ * ARMv8-a, AArch64
+ * Unaligned accesses
+ *
+ */
+
+/* By default we assume that the DC instruction can be used to zero
+   data blocks more efficiently.  In some circumstances this might be
+   unsafe, for example in an asymmetric multiprocessor environment with
+   different DC clear lengths (neither the upper nor lower lengths are
+   safe to use). */
+
+#define dst  		x0
+#define count		x2
+#define tmp1		x3
+#define tmp1w		w3
+#define tmp2		x4
+#define tmp2w		w4
+#define zva_len_x	x5
+#define zva_len		w5
+#define zva_bits_x	x6
+
+#define A_l		x1
+#define A_lw		w1
+#define tmp3w		w9
+
+#define ENTRY(f) \
+  .text; \
+  .globl f; \
+  .align 0; \
+  .type f, %function; \
+  f: \
+  .cfi_startproc \
+
+#define END(f) \
+  .cfi_endproc; \
+  .size f, .-f; \
+
+ENTRY(android_memset16)
+	ands   A_lw, A_lw, #0xffff
+	b.eq	.Lzero_mem
+	orr	A_lw, A_lw, A_lw, lsl #16
+	b .Lexpand_to_64
+END(android_memset16)
+
+ENTRY(android_memset32)
+	cmp	    A_lw, #0
+	b.eq	.Lzero_mem
+.Lexpand_to_64:
+	orr	A_l, A_l, A_l, lsl #32
+.Ltail_maybe_long:
+	cmp	count, #64
+	b.ge	.Lnot_short
+.Ltail_maybe_tiny:
+	cmp	count, #15
+	b.le	.Ltail15tiny
+.Ltail63:
+	ands	tmp1, count, #0x30
+	b.eq	.Ltail15
+	add	dst, dst, tmp1
+	cmp	tmp1w, #0x20
+	b.eq	1f
+	b.lt	2f
+	stp	A_l, A_l, [dst, #-48]
+1:
+	stp	A_l, A_l, [dst, #-32]
+2:
+	stp	A_l, A_l, [dst, #-16]
+
+.Ltail15:
+	and	count, count, #15
+	add	dst, dst, count
+	stp	A_l, A_l, [dst, #-16]	/* Repeat some/all of last store. */
+	ret
+
+.Ltail15tiny:
+	/* Set up to 15 bytes.  Does not assume earlier memory
+	   being set.  */
+	tbz	count, #3, 1f
+	str	A_l, [dst], #8
+1:
+	tbz	count, #2, 1f
+	str	A_lw, [dst], #4
+1:
+	tbz	count, #1, 1f
+	strh	A_lw, [dst], #2
+1:
+	ret
+
+	/* Critical loop.  Start at a new cache line boundary.  Assuming
+	 * 64 bytes per line, this ensures the entire loop is in one line.  */
+	.p2align 6
+.Lnot_short:
+	neg	tmp2, dst
+	ands	tmp2, tmp2, #15
+	b.eq	2f
+	/* Bring DST to 128-bit (16-byte) alignment.  We know that there's
+	 * more than that to set, so we simply store 16 bytes and advance by
+	 * the amount required to reach alignment.  */
+	sub	count, count, tmp2
+	stp	A_l, A_l, [dst]
+	add	dst, dst, tmp2
+	/* There may be less than 63 bytes to go now.  */
+	cmp	count, #63
+	b.le	.Ltail63
+2:
+	sub	dst, dst, #16		/* Pre-bias.  */
+	sub	count, count, #64
+1:
+	stp	A_l, A_l, [dst, #16]
+	stp	A_l, A_l, [dst, #32]
+	stp	A_l, A_l, [dst, #48]
+	stp	A_l, A_l, [dst, #64]!
+	subs	count, count, #64
+	b.ge	1b
+	tst	count, #0x3f
+	add	dst, dst, #16
+	b.ne	.Ltail63
+	ret
+
+	/* For zeroing memory, check to see if we can use the ZVA feature to
+	 * zero entire 'cache' lines.  */
+.Lzero_mem:
+	mov	A_l, #0
+	cmp	count, #63
+	b.le	.Ltail_maybe_tiny
+	neg	tmp2, dst
+	ands	tmp2, tmp2, #15
+	b.eq	1f
+	sub	count, count, tmp2
+	stp	A_l, A_l, [dst]
+	add	dst, dst, tmp2
+	cmp	count, #63
+	b.le	.Ltail63
+1:
+	/* For zeroing small amounts of memory, it's not worth setting up
+	 * the line-clear code.  */
+	cmp	count, #128
+	b.lt	.Lnot_short
+	mrs	tmp1, dczid_el0
+	tbnz	tmp1, #4, .Lnot_short
+	mov	tmp3w, #4
+	and	zva_len, tmp1w, #15	/* Safety: other bits reserved.  */
+	lsl	zva_len, tmp3w, zva_len
+
+.Lzero_by_line:
+	/* Compute how far we need to go to become suitably aligned.  We're
+	 * already at quad-word alignment.  */
+	cmp	count, zva_len_x
+	b.lt	.Lnot_short		/* Not enough to reach alignment.  */
+	sub	zva_bits_x, zva_len_x, #1
+	neg	tmp2, dst
+	ands	tmp2, tmp2, zva_bits_x
+	b.eq	1f			/* Already aligned.  */
+	/* Not aligned, check that there's enough to copy after alignment.  */
+	sub	tmp1, count, tmp2
+	cmp	tmp1, #64
+	ccmp	tmp1, zva_len_x, #8, ge	/* NZCV=0b1000 */
+	b.lt	.Lnot_short
+	/* We know that there's at least 64 bytes to zero and that it's safe
+	 * to overrun by 64 bytes.  */
+	mov	count, tmp1
+2:
+	stp	A_l, A_l, [dst]
+	stp	A_l, A_l, [dst, #16]
+	stp	A_l, A_l, [dst, #32]
+	subs	tmp2, tmp2, #64
+	stp	A_l, A_l, [dst, #48]
+	add	dst, dst, #64
+	b.ge	2b
+	/* We've overrun a bit, so adjust dst downwards.  */
+	add	dst, dst, tmp2
+1:
+	sub	count, count, zva_len_x
+3:
+	dc	zva, dst
+	add	dst, dst, zva_len_x
+	subs	count, count, zva_len_x
+	b.ge	3b
+	ands	count, count, zva_bits_x
+	b.ne	.Ltail_maybe_long
+	ret
+END(android_memset32)
diff --git a/libcutils/arch-x86/cache_wrapper.S b/libcutils/arch-x86/cache_wrapper.S
index 508fdd3..9eee25c 100644
--- a/libcutils/arch-x86/cache_wrapper.S
+++ b/libcutils/arch-x86/cache_wrapper.S
@@ -17,8 +17,15 @@
  * Contributed by: Intel Corporation
  */
 
+#if defined(__slm__)
+/* Values are optimized for Silvermont */
+#define SHARED_CACHE_SIZE   (1024*1024)         /* Silvermont L2 Cache */
+#define DATA_CACHE_SIZE     (24*1024)           /* Silvermont L1 Data Cache */
+#else
 /* Values are optimized for Atom */
-#define SHARED_CACHE_SIZE       (512*1024)            /* Atom L2 Cache */
-#define DATA_CACHE_SIZE         (24*1024)             /* Atom L1 Data Cache */
+#define SHARED_CACHE_SIZE   (512*1024)          /* Atom L2 Cache */
+#define DATA_CACHE_SIZE     (24*1024)           /* Atom L1 Data Cache */
+#endif
+
 #define SHARED_CACHE_SIZE_HALF  (SHARED_CACHE_SIZE / 2)
 #define DATA_CACHE_SIZE_HALF    (DATA_CACHE_SIZE / 2)
diff --git a/libcutils/arch-x86_64/android_memset16_SSE2-atom.S b/libcutils/arch-x86_64/android_memset16_SSE2-atom.S
new file mode 100644
index 0000000..48a10ed
--- /dev/null
+++ b/libcutils/arch-x86_64/android_memset16_SSE2-atom.S
@@ -0,0 +1,564 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+/*
+ * Contributed by: Intel Corporation
+ */
+
+#include "cache.h"
+
+#ifndef L
+# define L(label)	.L##label
+#endif
+
+#ifndef ALIGN
+# define ALIGN(n)	.p2align n
+#endif
+
+#ifndef cfi_startproc
+# define cfi_startproc			.cfi_startproc
+#endif
+
+#ifndef cfi_endproc
+# define cfi_endproc			.cfi_endproc
+#endif
+
+#ifndef ENTRY
+# define ENTRY(name)			\
+	.type name,  @function; 	\
+	.globl name;			\
+	.p2align 4;			\
+name:					\
+	cfi_startproc
+#endif
+
+#ifndef END
+# define END(name)			\
+	cfi_endproc;			\
+	.size name, .-name
+#endif
+
+#define JMPTBL(I, B)	I - B
+
+/* Branch to an entry in a jump table.  TABLE is a jump table with
+   relative offsets.  INDEX is a register contains the index into the
+   jump table.  SCALE is the scale of INDEX.  */
+#define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE) \
+	lea    TABLE(%rip), %r11;						\
+	movslq (%r11, INDEX, SCALE), INDEX;				\
+	lea    (%r11, INDEX), INDEX;					\
+	jmp    *INDEX
+
+	.section .text.sse2,"ax",@progbits
+	ALIGN (4)
+ENTRY (android_memset16)	// Address in rdi
+	shr    $1, %rdx			// Count in rdx
+	movzwl %si, %ecx
+	/* Fill the whole ECX with pattern.  */
+	shl    $16, %esi
+	or     %esi, %ecx		// Pattern in ecx
+
+	cmp    $32, %rdx
+	jae    L(32wordsormore)
+
+L(write_less32words):
+	lea    (%rdi, %rdx, 2), %rdi
+	BRANCH_TO_JMPTBL_ENTRY (L(table_less32words), %rdx, 4)
+
+	.pushsection .rodata.sse2,"a",@progbits
+	ALIGN (2)
+L(table_less32words):
+	.int	JMPTBL (L(write_0words), L(table_less32words))
+	.int	JMPTBL (L(write_1words), L(table_less32words))
+	.int	JMPTBL (L(write_2words), L(table_less32words))
+	.int	JMPTBL (L(write_3words), L(table_less32words))
+	.int	JMPTBL (L(write_4words), L(table_less32words))
+	.int	JMPTBL (L(write_5words), L(table_less32words))
+	.int	JMPTBL (L(write_6words), L(table_less32words))
+	.int	JMPTBL (L(write_7words), L(table_less32words))
+	.int	JMPTBL (L(write_8words), L(table_less32words))
+	.int	JMPTBL (L(write_9words), L(table_less32words))
+	.int	JMPTBL (L(write_10words), L(table_less32words))
+	.int	JMPTBL (L(write_11words), L(table_less32words))
+	.int	JMPTBL (L(write_12words), L(table_less32words))
+	.int	JMPTBL (L(write_13words), L(table_less32words))
+	.int	JMPTBL (L(write_14words), L(table_less32words))
+	.int	JMPTBL (L(write_15words), L(table_less32words))
+	.int	JMPTBL (L(write_16words), L(table_less32words))
+	.int	JMPTBL (L(write_17words), L(table_less32words))
+	.int	JMPTBL (L(write_18words), L(table_less32words))
+	.int	JMPTBL (L(write_19words), L(table_less32words))
+	.int	JMPTBL (L(write_20words), L(table_less32words))
+	.int	JMPTBL (L(write_21words), L(table_less32words))
+	.int	JMPTBL (L(write_22words), L(table_less32words))
+	.int	JMPTBL (L(write_23words), L(table_less32words))
+	.int	JMPTBL (L(write_24words), L(table_less32words))
+	.int	JMPTBL (L(write_25words), L(table_less32words))
+	.int	JMPTBL (L(write_26words), L(table_less32words))
+	.int	JMPTBL (L(write_27words), L(table_less32words))
+	.int	JMPTBL (L(write_28words), L(table_less32words))
+	.int	JMPTBL (L(write_29words), L(table_less32words))
+	.int	JMPTBL (L(write_30words), L(table_less32words))
+	.int	JMPTBL (L(write_31words), L(table_less32words))
+	.popsection
+
+	ALIGN (4)
+L(write_28words):
+	movl   %ecx, -56(%rdi)
+	movl   %ecx, -52(%rdi)
+L(write_24words):
+	movl   %ecx, -48(%rdi)
+	movl   %ecx, -44(%rdi)
+L(write_20words):
+	movl   %ecx, -40(%rdi)
+	movl   %ecx, -36(%rdi)
+L(write_16words):
+	movl   %ecx, -32(%rdi)
+	movl   %ecx, -28(%rdi)
+L(write_12words):
+	movl   %ecx, -24(%rdi)
+	movl   %ecx, -20(%rdi)
+L(write_8words):
+	movl   %ecx, -16(%rdi)
+	movl   %ecx, -12(%rdi)
+L(write_4words):
+	movl   %ecx, -8(%rdi)
+	movl   %ecx, -4(%rdi)
+L(write_0words):
+	ret
+
+	ALIGN (4)
+L(write_29words):
+	movl   %ecx, -58(%rdi)
+	movl   %ecx, -54(%rdi)
+L(write_25words):
+	movl   %ecx, -50(%rdi)
+	movl   %ecx, -46(%rdi)
+L(write_21words):
+	movl   %ecx, -42(%rdi)
+	movl   %ecx, -38(%rdi)
+L(write_17words):
+	movl   %ecx, -34(%rdi)
+	movl   %ecx, -30(%rdi)
+L(write_13words):
+	movl   %ecx, -26(%rdi)
+	movl   %ecx, -22(%rdi)
+L(write_9words):
+	movl   %ecx, -18(%rdi)
+	movl   %ecx, -14(%rdi)
+L(write_5words):
+	movl   %ecx, -10(%rdi)
+	movl   %ecx, -6(%rdi)
+L(write_1words):
+	mov	%cx, -2(%rdi)
+	ret
+
+	ALIGN (4)
+L(write_30words):
+	movl   %ecx, -60(%rdi)
+	movl   %ecx, -56(%rdi)
+L(write_26words):
+	movl   %ecx, -52(%rdi)
+	movl   %ecx, -48(%rdi)
+L(write_22words):
+	movl   %ecx, -44(%rdi)
+	movl   %ecx, -40(%rdi)
+L(write_18words):
+	movl   %ecx, -36(%rdi)
+	movl   %ecx, -32(%rdi)
+L(write_14words):
+	movl   %ecx, -28(%rdi)
+	movl   %ecx, -24(%rdi)
+L(write_10words):
+	movl   %ecx, -20(%rdi)
+	movl   %ecx, -16(%rdi)
+L(write_6words):
+	movl   %ecx, -12(%rdi)
+	movl   %ecx, -8(%rdi)
+L(write_2words):
+	movl   %ecx, -4(%rdi)
+	ret
+
+	ALIGN (4)
+L(write_31words):
+	movl   %ecx, -62(%rdi)
+	movl   %ecx, -58(%rdi)
+L(write_27words):
+	movl   %ecx, -54(%rdi)
+	movl   %ecx, -50(%rdi)
+L(write_23words):
+	movl   %ecx, -46(%rdi)
+	movl   %ecx, -42(%rdi)
+L(write_19words):
+	movl   %ecx, -38(%rdi)
+	movl   %ecx, -34(%rdi)
+L(write_15words):
+	movl   %ecx, -30(%rdi)
+	movl   %ecx, -26(%rdi)
+L(write_11words):
+	movl   %ecx, -22(%rdi)
+	movl   %ecx, -18(%rdi)
+L(write_7words):
+	movl   %ecx, -14(%rdi)
+	movl   %ecx, -10(%rdi)
+L(write_3words):
+	movl   %ecx, -6(%rdi)
+	movw   %cx, -2(%rdi)
+	ret
+
+	ALIGN (4)
+L(32wordsormore):
+	shl    $1, %rdx
+	test   $0x01, %edi
+	jz     L(aligned2bytes)
+	mov    %ecx, (%rdi)
+	mov    %ecx, -4(%rdi, %rdx)
+	sub    $2, %rdx
+	add    $1, %rdi
+	rol    $8, %ecx
+L(aligned2bytes):
+	/* Fill xmm0 with the pattern.  */
+	movd   %ecx, %xmm0
+	pshufd $0, %xmm0, %xmm0
+
+	testl  $0xf, %edi
+	jz     L(aligned_16)
+/* RDX > 32 and RDI is not 16 byte aligned.  */
+	movdqu %xmm0, (%rdi)
+	mov    %rdi, %rsi
+	and    $-16, %rdi
+	add    $16, %rdi
+	sub    %rdi, %rsi
+	add    %rsi, %rdx
+
+	ALIGN (4)
+L(aligned_16):
+	cmp    $128, %rdx
+	jge    L(128bytesormore)
+
+L(aligned_16_less128bytes):
+	add    %rdx, %rdi
+	shr    $1, %rdx
+	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+	ALIGN (4)
+L(128bytesormore):
+	cmp    $SHARED_CACHE_SIZE, %rdx
+	jg     L(128bytesormore_nt)
+
+L(128bytesormore_normal):
+	sub    $128, %rdx
+	movdqa %xmm0, (%rdi)
+	movdqa %xmm0, 0x10(%rdi)
+	movdqa %xmm0, 0x20(%rdi)
+	movdqa %xmm0, 0x30(%rdi)
+	movdqa %xmm0, 0x40(%rdi)
+	movdqa %xmm0, 0x50(%rdi)
+	movdqa %xmm0, 0x60(%rdi)
+	movdqa %xmm0, 0x70(%rdi)
+	lea    128(%rdi), %rdi
+	cmp    $128, %rdx
+	jl     L(128bytesless_normal)
+
+	sub    $128, %rdx
+	movdqa %xmm0, (%rdi)
+	movdqa %xmm0, 0x10(%rdi)
+	movdqa %xmm0, 0x20(%rdi)
+	movdqa %xmm0, 0x30(%rdi)
+	movdqa %xmm0, 0x40(%rdi)
+	movdqa %xmm0, 0x50(%rdi)
+	movdqa %xmm0, 0x60(%rdi)
+	movdqa %xmm0, 0x70(%rdi)
+	lea    128(%rdi), %rdi
+	cmp    $128, %rdx
+	jl     L(128bytesless_normal)
+
+	sub    $128, %rdx
+	movdqa %xmm0, (%rdi)
+	movdqa %xmm0, 0x10(%rdi)
+	movdqa %xmm0, 0x20(%rdi)
+	movdqa %xmm0, 0x30(%rdi)
+	movdqa %xmm0, 0x40(%rdi)
+	movdqa %xmm0, 0x50(%rdi)
+	movdqa %xmm0, 0x60(%rdi)
+	movdqa %xmm0, 0x70(%rdi)
+	lea    128(%rdi), %rdi
+	cmp    $128, %rdx
+	jl     L(128bytesless_normal)
+
+	sub    $128, %rdx
+	movdqa %xmm0, (%rdi)
+	movdqa %xmm0, 0x10(%rdi)
+	movdqa %xmm0, 0x20(%rdi)
+	movdqa %xmm0, 0x30(%rdi)
+	movdqa %xmm0, 0x40(%rdi)
+	movdqa %xmm0, 0x50(%rdi)
+	movdqa %xmm0, 0x60(%rdi)
+	movdqa %xmm0, 0x70(%rdi)
+	lea    128(%rdi), %rdi
+	cmp    $128, %rdx
+	jge    L(128bytesormore_normal)
+
+L(128bytesless_normal):
+	add    %rdx, %rdi
+	shr    $1, %rdx
+	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+	ALIGN (4)
+L(128bytesormore_nt):
+	sub    $128, %rdx
+	movntdq %xmm0, (%rdi)
+	movntdq %xmm0, 0x10(%rdi)
+	movntdq %xmm0, 0x20(%rdi)
+	movntdq %xmm0, 0x30(%rdi)
+	movntdq %xmm0, 0x40(%rdi)
+	movntdq %xmm0, 0x50(%rdi)
+	movntdq %xmm0, 0x60(%rdi)
+	movntdq %xmm0, 0x70(%rdi)
+	lea    128(%rdi), %rdi
+	cmp    $128, %rdx
+	jge    L(128bytesormore_nt)
+
+	sfence
+	add    %rdx, %rdi
+	shr    $1, %rdx
+	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+	.pushsection .rodata.sse2,"a",@progbits
+	ALIGN (2)
+L(table_16_128bytes):
+	.int	JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_2bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_6bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_10bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_14bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_18bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_22bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_26bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_30bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_34bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_38bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_42bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_46bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_50bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_54bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_58bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_62bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_66bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_70bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_74bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_78bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_82bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_86bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_90bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_94bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_98bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_102bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_106bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_110bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_114bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_118bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_122bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_126bytes), L(table_16_128bytes))
+	.popsection
+
+	ALIGN (4)
+L(aligned_16_112bytes):
+	movdqa %xmm0, -112(%rdi)
+L(aligned_16_96bytes):
+	movdqa %xmm0, -96(%rdi)
+L(aligned_16_80bytes):
+	movdqa %xmm0, -80(%rdi)
+L(aligned_16_64bytes):
+	movdqa %xmm0, -64(%rdi)
+L(aligned_16_48bytes):
+	movdqa %xmm0, -48(%rdi)
+L(aligned_16_32bytes):
+	movdqa %xmm0, -32(%rdi)
+L(aligned_16_16bytes):
+	movdqa %xmm0, -16(%rdi)
+L(aligned_16_0bytes):
+	ret
+
+	ALIGN (4)
+L(aligned_16_114bytes):
+	movdqa %xmm0, -114(%rdi)
+L(aligned_16_98bytes):
+	movdqa %xmm0, -98(%rdi)
+L(aligned_16_82bytes):
+	movdqa %xmm0, -82(%rdi)
+L(aligned_16_66bytes):
+	movdqa %xmm0, -66(%rdi)
+L(aligned_16_50bytes):
+	movdqa %xmm0, -50(%rdi)
+L(aligned_16_34bytes):
+	movdqa %xmm0, -34(%rdi)
+L(aligned_16_18bytes):
+	movdqa %xmm0, -18(%rdi)
+L(aligned_16_2bytes):
+	movw   %cx, -2(%rdi)
+	ret
+
+	ALIGN (4)
+L(aligned_16_116bytes):
+	movdqa %xmm0, -116(%rdi)
+L(aligned_16_100bytes):
+	movdqa %xmm0, -100(%rdi)
+L(aligned_16_84bytes):
+	movdqa %xmm0, -84(%rdi)
+L(aligned_16_68bytes):
+	movdqa %xmm0, -68(%rdi)
+L(aligned_16_52bytes):
+	movdqa %xmm0, -52(%rdi)
+L(aligned_16_36bytes):
+	movdqa %xmm0, -36(%rdi)
+L(aligned_16_20bytes):
+	movdqa %xmm0, -20(%rdi)
+L(aligned_16_4bytes):
+	movl   %ecx, -4(%rdi)
+	ret
+
+	ALIGN (4)
+L(aligned_16_118bytes):
+	movdqa %xmm0, -118(%rdi)
+L(aligned_16_102bytes):
+	movdqa %xmm0, -102(%rdi)
+L(aligned_16_86bytes):
+	movdqa %xmm0, -86(%rdi)
+L(aligned_16_70bytes):
+	movdqa %xmm0, -70(%rdi)
+L(aligned_16_54bytes):
+	movdqa %xmm0, -54(%rdi)
+L(aligned_16_38bytes):
+	movdqa %xmm0, -38(%rdi)
+L(aligned_16_22bytes):
+	movdqa %xmm0, -22(%rdi)
+L(aligned_16_6bytes):
+	movl   %ecx, -6(%rdi)
+	movw   %cx, -2(%rdi)
+	ret
+
+	ALIGN (4)
+L(aligned_16_120bytes):
+	movdqa %xmm0, -120(%rdi)
+L(aligned_16_104bytes):
+	movdqa %xmm0, -104(%rdi)
+L(aligned_16_88bytes):
+	movdqa %xmm0, -88(%rdi)
+L(aligned_16_72bytes):
+	movdqa %xmm0, -72(%rdi)
+L(aligned_16_56bytes):
+	movdqa %xmm0, -56(%rdi)
+L(aligned_16_40bytes):
+	movdqa %xmm0, -40(%rdi)
+L(aligned_16_24bytes):
+	movdqa %xmm0, -24(%rdi)
+L(aligned_16_8bytes):
+	movq   %xmm0, -8(%rdi)
+	ret
+
+	ALIGN (4)
+L(aligned_16_122bytes):
+	movdqa %xmm0, -122(%rdi)
+L(aligned_16_106bytes):
+	movdqa %xmm0, -106(%rdi)
+L(aligned_16_90bytes):
+	movdqa %xmm0, -90(%rdi)
+L(aligned_16_74bytes):
+	movdqa %xmm0, -74(%rdi)
+L(aligned_16_58bytes):
+	movdqa %xmm0, -58(%rdi)
+L(aligned_16_42bytes):
+	movdqa %xmm0, -42(%rdi)
+L(aligned_16_26bytes):
+	movdqa %xmm0, -26(%rdi)
+L(aligned_16_10bytes):
+	movq   %xmm0, -10(%rdi)
+	movw   %cx, -2(%rdi)
+	ret
+
+	ALIGN (4)
+L(aligned_16_124bytes):
+	movdqa %xmm0, -124(%rdi)
+L(aligned_16_108bytes):
+	movdqa %xmm0, -108(%rdi)
+L(aligned_16_92bytes):
+	movdqa %xmm0, -92(%rdi)
+L(aligned_16_76bytes):
+	movdqa %xmm0, -76(%rdi)
+L(aligned_16_60bytes):
+	movdqa %xmm0, -60(%rdi)
+L(aligned_16_44bytes):
+	movdqa %xmm0, -44(%rdi)
+L(aligned_16_28bytes):
+	movdqa %xmm0, -28(%rdi)
+L(aligned_16_12bytes):
+	movq   %xmm0, -12(%rdi)
+	movl   %ecx, -4(%rdi)
+	ret
+
+	ALIGN (4)
+L(aligned_16_126bytes):
+	movdqa %xmm0, -126(%rdi)
+L(aligned_16_110bytes):
+	movdqa %xmm0, -110(%rdi)
+L(aligned_16_94bytes):
+	movdqa %xmm0, -94(%rdi)
+L(aligned_16_78bytes):
+	movdqa %xmm0, -78(%rdi)
+L(aligned_16_62bytes):
+	movdqa %xmm0, -62(%rdi)
+L(aligned_16_46bytes):
+	movdqa %xmm0, -46(%rdi)
+L(aligned_16_30bytes):
+	movdqa %xmm0, -30(%rdi)
+L(aligned_16_14bytes):
+	movq   %xmm0, -14(%rdi)
+	movl   %ecx, -6(%rdi)
+	movw   %cx, -2(%rdi)
+	ret
+
+END (android_memset16)
diff --git a/libcutils/arch-x86_64/android_memset32_SSE2-atom.S b/libcutils/arch-x86_64/android_memset32_SSE2-atom.S
new file mode 100644
index 0000000..4bdea8e
--- /dev/null
+++ b/libcutils/arch-x86_64/android_memset32_SSE2-atom.S
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+/*
+ * Contributed by: Intel Corporation
+ */
+
+#include "cache.h"
+
+#ifndef L
+# define L(label)	.L##label
+#endif
+
+#ifndef ALIGN
+# define ALIGN(n)	.p2align n
+#endif
+
+#ifndef cfi_startproc
+# define cfi_startproc			.cfi_startproc
+#endif
+
+#ifndef cfi_endproc
+# define cfi_endproc			.cfi_endproc
+#endif
+
+#ifndef ENTRY
+# define ENTRY(name)			\
+	.type name,  @function; 	\
+	.globl name;			\
+	.p2align 4;			\
+name:					\
+	cfi_startproc
+#endif
+
+#ifndef END
+# define END(name)			\
+	cfi_endproc;			\
+	.size name, .-name
+#endif
+
+#define JMPTBL(I, B)	I - B
+
+/* Branch to an entry in a jump table.  TABLE is a jump table with
+   relative offsets.  INDEX is a register contains the index into the
+   jump table.  SCALE is the scale of INDEX.  */
+#define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE) \
+	lea    TABLE(%rip), %r11;						\
+	movslq (%r11, INDEX, SCALE), INDEX;				\
+	lea    (%r11, INDEX), INDEX;					\
+	jmp    *INDEX
+
+	.section .text.sse2,"ax",@progbits
+	ALIGN (4)
+ENTRY (android_memset32)	// Address in rdi
+	shr    $2, %rdx			// Count in rdx
+	movl   %esi, %ecx		// Pattern in ecx
+
+	cmp    $16, %rdx
+	jae    L(16dbwordsormore)
+
+L(write_less16dbwords):
+	lea    (%rdi, %rdx, 4), %rdi
+	BRANCH_TO_JMPTBL_ENTRY (L(table_less16dbwords), %rdx, 4)
+
+	.pushsection .rodata.sse2,"a",@progbits
+	ALIGN (2)
+L(table_less16dbwords):
+	.int	JMPTBL (L(write_0dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_1dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_2dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_3dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_4dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_5dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_6dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_7dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_8dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_9dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_10dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_11dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_12dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_13dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_14dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_15dbwords), L(table_less16dbwords))
+	.popsection
+
+	ALIGN (4)
+L(write_15dbwords):
+	movl   %ecx, -60(%rdi)
+L(write_14dbwords):
+	movl   %ecx, -56(%rdi)
+L(write_13dbwords):
+	movl   %ecx, -52(%rdi)
+L(write_12dbwords):
+	movl   %ecx, -48(%rdi)
+L(write_11dbwords):
+	movl   %ecx, -44(%rdi)
+L(write_10dbwords):
+	movl   %ecx, -40(%rdi)
+L(write_9dbwords):
+	movl   %ecx, -36(%rdi)
+L(write_8dbwords):
+	movl   %ecx, -32(%rdi)
+L(write_7dbwords):
+	movl   %ecx, -28(%rdi)
+L(write_6dbwords):
+	movl   %ecx, -24(%rdi)
+L(write_5dbwords):
+	movl   %ecx, -20(%rdi)
+L(write_4dbwords):
+	movl   %ecx, -16(%rdi)
+L(write_3dbwords):
+	movl   %ecx, -12(%rdi)
+L(write_2dbwords):
+	movl   %ecx, -8(%rdi)
+L(write_1dbwords):
+	movl   %ecx, -4(%rdi)
+L(write_0dbwords):
+	ret
+
+	ALIGN (4)
+L(16dbwordsormore):
+	test   $3, %edi
+	jz     L(aligned4bytes)
+	mov    %ecx, (%rdi)
+	mov    %ecx, -4(%rdi, %rdx, 4)
+	sub    $1, %rdx
+	rol    $24, %ecx
+	add    $1, %rdi
+	test   $3, %edi
+	jz     L(aligned4bytes)
+	ror    $8, %ecx
+	add    $1, %rdi
+	test   $3, %edi
+	jz     L(aligned4bytes)
+	ror    $8, %ecx
+	add    $1, %rdi
+L(aligned4bytes):
+	shl    $2, %rdx
+
+	/* Fill xmm0 with the pattern.  */
+	movd   %ecx, %xmm0
+	pshufd $0, %xmm0, %xmm0
+
+	testl  $0xf, %edi
+	jz     L(aligned_16)
+/* RDX > 32 and RDI is not 16 byte aligned.  */
+	movdqu %xmm0, (%rdi)
+	mov    %rdi, %rsi
+	and    $-16, %rdi
+	add    $16, %rdi
+	sub    %rdi, %rsi
+	add    %rsi, %rdx
+
+	ALIGN (4)
+L(aligned_16):
+	cmp    $128, %rdx
+	jge    L(128bytesormore)
+
+L(aligned_16_less128bytes):
+	add    %rdx, %rdi
+	shr    $2, %rdx
+	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+	ALIGN (4)
+L(128bytesormore):
+	cmp    $SHARED_CACHE_SIZE, %rdx
+	jg     L(128bytesormore_nt)
+
+L(128bytesormore_normal):
+	sub    $128, %rdx
+	movdqa %xmm0, (%rdi)
+	movdqa %xmm0, 0x10(%rdi)
+	movdqa %xmm0, 0x20(%rdi)
+	movdqa %xmm0, 0x30(%rdi)
+	movdqa %xmm0, 0x40(%rdi)
+	movdqa %xmm0, 0x50(%rdi)
+	movdqa %xmm0, 0x60(%rdi)
+	movdqa %xmm0, 0x70(%rdi)
+	lea    128(%rdi), %rdi
+	cmp    $128, %rdx
+	jl     L(128bytesless_normal)
+
+	sub    $128, %rdx
+	movdqa %xmm0, (%rdi)
+	movdqa %xmm0, 0x10(%rdi)
+	movdqa %xmm0, 0x20(%rdi)
+	movdqa %xmm0, 0x30(%rdi)
+	movdqa %xmm0, 0x40(%rdi)
+	movdqa %xmm0, 0x50(%rdi)
+	movdqa %xmm0, 0x60(%rdi)
+	movdqa %xmm0, 0x70(%rdi)
+	lea    128(%rdi), %rdi
+	cmp    $128, %rdx
+	jl     L(128bytesless_normal)
+
+	sub    $128, %rdx
+	movdqa %xmm0, (%rdi)
+	movdqa %xmm0, 0x10(%rdi)
+	movdqa %xmm0, 0x20(%rdi)
+	movdqa %xmm0, 0x30(%rdi)
+	movdqa %xmm0, 0x40(%rdi)
+	movdqa %xmm0, 0x50(%rdi)
+	movdqa %xmm0, 0x60(%rdi)
+	movdqa %xmm0, 0x70(%rdi)
+	lea    128(%rdi), %rdi
+	cmp    $128, %rdx
+	jl     L(128bytesless_normal)
+
+	sub    $128, %rdx
+	movdqa %xmm0, (%rdi)
+	movdqa %xmm0, 0x10(%rdi)
+	movdqa %xmm0, 0x20(%rdi)
+	movdqa %xmm0, 0x30(%rdi)
+	movdqa %xmm0, 0x40(%rdi)
+	movdqa %xmm0, 0x50(%rdi)
+	movdqa %xmm0, 0x60(%rdi)
+	movdqa %xmm0, 0x70(%rdi)
+	lea    128(%rdi), %rdi
+	cmp    $128, %rdx
+	jge    L(128bytesormore_normal)
+
+L(128bytesless_normal):
+	add    %rdx, %rdi
+	shr    $2, %rdx
+	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+	ALIGN (4)
+L(128bytesormore_nt):
+	sub    $128, %rdx
+	movntdq %xmm0, (%rdi)
+	movntdq %xmm0, 0x10(%rdi)
+	movntdq %xmm0, 0x20(%rdi)
+	movntdq %xmm0, 0x30(%rdi)
+	movntdq %xmm0, 0x40(%rdi)
+	movntdq %xmm0, 0x50(%rdi)
+	movntdq %xmm0, 0x60(%rdi)
+	movntdq %xmm0, 0x70(%rdi)
+	lea    128(%rdi), %rdi
+	cmp    $128, %rdx
+	jge    L(128bytesormore_nt)
+
+	sfence
+	add    %rdx, %rdi
+	shr    $2, %rdx
+	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+	.pushsection .rodata.sse2,"a",@progbits
+	ALIGN (2)
+L(table_16_128bytes):
+	.int	JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes))
+	.popsection
+
+	ALIGN (4)
+L(aligned_16_112bytes):
+	movdqa	%xmm0, -112(%rdi)
+L(aligned_16_96bytes):
+	movdqa	%xmm0, -96(%rdi)
+L(aligned_16_80bytes):
+	movdqa	%xmm0, -80(%rdi)
+L(aligned_16_64bytes):
+	movdqa	%xmm0, -64(%rdi)
+L(aligned_16_48bytes):
+	movdqa	%xmm0, -48(%rdi)
+L(aligned_16_32bytes):
+	movdqa	%xmm0, -32(%rdi)
+L(aligned_16_16bytes):
+	movdqa	%xmm0, -16(%rdi)
+L(aligned_16_0bytes):
+	ret
+
+	ALIGN (4)
+L(aligned_16_116bytes):
+	movdqa	%xmm0, -116(%rdi)
+L(aligned_16_100bytes):
+	movdqa	%xmm0, -100(%rdi)
+L(aligned_16_84bytes):
+	movdqa	%xmm0, -84(%rdi)
+L(aligned_16_68bytes):
+	movdqa	%xmm0, -68(%rdi)
+L(aligned_16_52bytes):
+	movdqa	%xmm0, -52(%rdi)
+L(aligned_16_36bytes):
+	movdqa	%xmm0, -36(%rdi)
+L(aligned_16_20bytes):
+	movdqa	%xmm0, -20(%rdi)
+L(aligned_16_4bytes):
+	movl	%ecx, -4(%rdi)
+	ret
+
+	ALIGN (4)
+L(aligned_16_120bytes):
+	movdqa	%xmm0, -120(%rdi)
+L(aligned_16_104bytes):
+	movdqa	%xmm0, -104(%rdi)
+L(aligned_16_88bytes):
+	movdqa	%xmm0, -88(%rdi)
+L(aligned_16_72bytes):
+	movdqa	%xmm0, -72(%rdi)
+L(aligned_16_56bytes):
+	movdqa	%xmm0, -56(%rdi)
+L(aligned_16_40bytes):
+	movdqa	%xmm0, -40(%rdi)
+L(aligned_16_24bytes):
+	movdqa	%xmm0, -24(%rdi)
+L(aligned_16_8bytes):
+	movq	%xmm0, -8(%rdi)
+	ret
+
+	ALIGN (4)
+L(aligned_16_124bytes):
+	movdqa	%xmm0, -124(%rdi)
+L(aligned_16_108bytes):
+	movdqa	%xmm0, -108(%rdi)
+L(aligned_16_92bytes):
+	movdqa	%xmm0, -92(%rdi)
+L(aligned_16_76bytes):
+	movdqa	%xmm0, -76(%rdi)
+L(aligned_16_60bytes):
+	movdqa	%xmm0, -60(%rdi)
+L(aligned_16_44bytes):
+	movdqa	%xmm0, -44(%rdi)
+L(aligned_16_28bytes):
+	movdqa	%xmm0, -28(%rdi)
+L(aligned_16_12bytes):
+	movq	%xmm0, -12(%rdi)
+	movl	%ecx, -4(%rdi)
+	ret
+
+END (android_memset32)
diff --git a/libcutils/arch-x86_64/cache.h b/libcutils/arch-x86_64/cache.h
new file mode 100644
index 0000000..ab5dd2f
--- /dev/null
+++ b/libcutils/arch-x86_64/cache.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+/*
+ * Contributed by: Intel Corporation
+ */
+
+#if defined(__slm__)
+/* Values are optimized for Silvermont */
+#define SHARED_CACHE_SIZE	(1024*1024)			/* Silvermont L2 Cache */
+#define DATA_CACHE_SIZE		(24*1024)			/* Silvermont L1 Data Cache */
+#else
+/* Values are optimized for Atom */
+#define SHARED_CACHE_SIZE	(512*1024)			/* Atom L2 Cache */
+#define DATA_CACHE_SIZE		(24*1024)			/* Atom L1 Data Cache */
+#endif
+
+#define SHARED_CACHE_SIZE_HALF	(SHARED_CACHE_SIZE / 2)
+#define DATA_CACHE_SIZE_HALF	(DATA_CACHE_SIZE / 2)
diff --git a/libcutils/ashmem-host.c b/libcutils/ashmem-host.c
index f03e130..4ac4f57 100644
--- a/libcutils/ashmem-host.c
+++ b/libcutils/ashmem-host.c
@@ -19,96 +19,102 @@
  * an ashmem-enabled kernel. See ashmem-dev.c for the real ashmem-based version.
  */
 
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdio.h>
 #include <errno.h>
-#include <time.h>
+#include <fcntl.h>
 #include <limits.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
 
 #include <cutils/ashmem.h>
 
-int ashmem_create_region(const char *ignored, size_t size)
-{
-	static const char txt[] = "abcdefghijklmnopqrstuvwxyz"
-				  "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-	char name[64];
-	unsigned int retries = 0;
-	pid_t pid = getpid();
-	int fd;
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
 
-	srand(time(NULL) + pid);
-
-retry:
-	/* not beautiful, its just wolf-like loop unrolling */
-	snprintf(name, sizeof(name), "/tmp/android-ashmem-%d-%c%c%c%c%c%c%c%c",
-		pid,
-		txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
-		txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
-		txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
-		txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
-		txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
-		txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
-		txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
-		txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))]);
-
-	/* open O_EXCL & O_CREAT: we are either the sole owner or we fail */
-	fd = open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
-	if (fd == -1) {
-		/* unlikely, but if we failed because `name' exists, retry */
-		if (errno == EEXIST && ++retries < 6)
-			goto retry;
-		return -1;
-	}
-
-	/* truncate the file to `len' bytes */
-	if (ftruncate(fd, size) == -1)
-		goto error;
-
-	if (unlink(name) == -1)
-		goto error;
-
-	return fd;
-error:
-	close(fd);
-	return -1;
+static pthread_once_t seed_initialized = PTHREAD_ONCE_INIT;
+static void initialize_random() {
+    srand(time(NULL) + getpid());
 }
 
-int ashmem_set_prot_region(int fd, int prot)
+int ashmem_create_region(const char *ignored __unused, size_t size)
 {
-	return 0;
+    static const char txt[] = "abcdefghijklmnopqrstuvwxyz"
+            "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+    char name[64];
+    unsigned int retries = 0;
+    pid_t pid = getpid();
+    int fd;
+    if (pthread_once(&seed_initialized, &initialize_random) != 0) {
+        return -1;
+    }
+    do {
+        /* not beautiful, its just wolf-like loop unrolling */
+        snprintf(name, sizeof(name), "/tmp/android-ashmem-%d-%c%c%c%c%c%c%c%c",
+        pid,
+        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
+        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
+        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
+        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
+        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
+        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
+        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
+        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))]);
+
+        /* open O_EXCL & O_CREAT: we are either the sole owner or we fail */
+        fd = open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
+        if (fd == -1) {
+            /* unlikely, but if we failed because `name' exists, retry */
+            if (errno != EEXIST || ++retries >= 6) {
+                return -1;
+            }
+        }
+    } while (fd == -1);
+    /* truncate the file to `len' bytes */
+    if (ftruncate(fd, size) != -1 && unlink(name) != -1) {
+        return fd;
+    }
+    close(fd);
+    return -1;
 }
 
-int ashmem_pin_region(int fd, size_t offset, size_t len)
+int ashmem_set_prot_region(int fd __unused, int prot __unused)
 {
-	return ASHMEM_NOT_PURGED;
+    return 0;
 }
 
-int ashmem_unpin_region(int fd, size_t offset, size_t len)
+int ashmem_pin_region(int fd __unused, size_t offset __unused, size_t len __unused)
 {
-	return ASHMEM_IS_UNPINNED;
+    return ASHMEM_NOT_PURGED;
+}
+
+int ashmem_unpin_region(int fd __unused, size_t offset __unused, size_t len __unused)
+{
+    return ASHMEM_IS_UNPINNED;
 }
 
 int ashmem_get_size_region(int fd)
 {
-        struct stat buf;
-        int result;
+    struct stat buf;
+    int result;
 
-        result = fstat(fd, &buf);
-        if (result == -1) {
-                return -1;
-        }
+    result = fstat(fd, &buf);
+    if (result == -1) {
+        return -1;
+    }
 
-        // Check if this is an "ashmem" region.
-        // TODO: This is very hacky, and can easily break. We need some reliable indicator.
-        if (!(buf.st_nlink == 0 && S_ISREG(buf.st_mode))) {
-                errno = ENOTTY;
-                return -1;
-        }
+    // Check if this is an "ashmem" region.
+    // TODO: This is very hacky, and can easily break. We need some reliable indicator.
+    if (!(buf.st_nlink == 0 && S_ISREG(buf.st_mode))) {
+        errno = ENOTTY;
+        return -1;
+    }
 
-        return (int)buf.st_size;  // TODO: care about overflow (> 2GB file)?
+    return (int)buf.st_size;    // TODO: care about overflow (> 2GB file)?
 }
diff --git a/libcutils/cpu_info.c b/libcutils/cpu_info.c
index 23dda8a..21fa1dc 100644
--- a/libcutils/cpu_info.c
+++ b/libcutils/cpu_info.c
@@ -1,5 +1,4 @@
-/* libs/cutils/cpu_info.c
-**
+/*
 ** Copyright 2007, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License"); 
@@ -15,11 +14,12 @@
 ** limitations under the License.
 */
 
-#include <cutils/cpu_info.h>
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
+#include <cutils/cpu_info.h>
+
 // we cache the serial number here.
 // this is also used as a fgets() line buffer when we are reading /proc/cpuinfo
 static char serial_number[100] = { 0 };
@@ -31,7 +31,6 @@
         FILE* file;
         char* chp, *end;
         char* whitespace;
-        int length;
         
         // read serial number from /proc/cpuinfo
         file = fopen("proc/cpuinfo", "r");
diff --git a/libcutils/debugger.c b/libcutils/debugger.c
index 7d907fc..056de5d 100644
--- a/libcutils/debugger.c
+++ b/libcutils/debugger.c
@@ -15,6 +15,7 @@
  */
 
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
 #include <cutils/debugger.h>
@@ -28,9 +29,9 @@
     }
 
     debugger_msg_t msg;
+    memset(&msg, 0, sizeof(msg));
     msg.tid = tid;
     msg.action = DEBUGGER_ACTION_DUMP_TOMBSTONE;
-    msg.abort_msg_address = 0;
 
     int result = 0;
     if (TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))) != sizeof(msg)) {
@@ -62,9 +63,9 @@
     }
 
     debugger_msg_t msg;
+    memset(&msg, 0, sizeof(msg));
     msg.tid = tid;
     msg.action = DEBUGGER_ACTION_DUMP_BACKTRACE;
-    msg.abort_msg_address = 0;
 
     int result = 0;
     if (TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))) != sizeof(msg)) {
diff --git a/libcutils/dlmalloc_stubs.c b/libcutils/dlmalloc_stubs.c
index c327a55..2db473d 100644
--- a/libcutils/dlmalloc_stubs.c
+++ b/libcutils/dlmalloc_stubs.c
@@ -14,21 +14,22 @@
  * limitations under the License.
  */
 
-#include "../../../bionic/libc/bionic/dlmalloc.h"
-#include "cutils/log.h"
+#include "log/log.h"
+
+#define UNUSED __attribute__((__unused__))
 
 /*
  * Stubs for functions defined in bionic/libc/bionic/dlmalloc.c. These
  * are used in host builds, as the host libc will not contain these
  * functions.
  */
-void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*),
-                          void* arg)
+void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*) UNUSED,
+                          void* arg UNUSED)
 {
   ALOGW("Called host unimplemented stub: dlmalloc_inspect_all");
 }
 
-int dlmalloc_trim(size_t unused)
+int dlmalloc_trim(size_t unused UNUSED)
 {
   ALOGW("Called host unimplemented stub: dlmalloc_trim");
   return 0;
diff --git a/libcutils/iosched_policy.c b/libcutils/iosched_policy.c
index 5d90a01..a6da9ca 100644
--- a/libcutils/iosched_policy.c
+++ b/libcutils/iosched_policy.c
@@ -1,5 +1,4 @@
 /*
-**
 ** Copyright 2007-2014, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License"); 
@@ -15,50 +14,41 @@
 ** limitations under the License.
 */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
 #include <errno.h>
 #include <fcntl.h>
-
-#ifdef HAVE_SCHED_H
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
 
 #include <cutils/iosched_policy.h>
 
 #ifdef HAVE_ANDROID_OS
-/* #include <linux/ioprio.h> */
-extern int ioprio_set(int which, int who, int ioprio);
-extern int ioprio_get(int which, int who);
+#include <linux/ioprio.h>
+#include <sys/syscall.h>
+#define __android_unused
+#else
+#define __android_unused __attribute__((__unused__))
 #endif
 
-enum {
-    WHO_PROCESS = 1,
-    WHO_PGRP,
-    WHO_USER,
-};
-
-#define CLASS_SHIFT 13
-#define IOPRIO_NORM 4
-
-int android_set_ioprio(int pid, IoSchedClass clazz, int ioprio) {
+int android_set_ioprio(int pid __android_unused, IoSchedClass clazz __android_unused, int ioprio __android_unused) {
 #ifdef HAVE_ANDROID_OS
-    if (ioprio_set(WHO_PROCESS, pid, ioprio | (clazz << CLASS_SHIFT))) {
+    if (syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, pid, ioprio | (clazz << IOPRIO_CLASS_SHIFT))) {
         return -1;
     }
 #endif
     return 0;
 }
 
-int android_get_ioprio(int pid, IoSchedClass *clazz, int *ioprio) {
+int android_get_ioprio(int pid __android_unused, IoSchedClass *clazz, int *ioprio) {
 #ifdef HAVE_ANDROID_OS
     int rc;
 
-    if ((rc = ioprio_get(WHO_PROCESS, pid)) < 0) {
+    if ((rc = syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, pid)) < 0) {
         return -1;
     }
 
-    *clazz = (rc >> CLASS_SHIFT);
+    *clazz = (rc >> IOPRIO_CLASS_SHIFT);
     *ioprio = (rc & 0xff);
 #else
     *clazz = IoSchedClass_NONE;
@@ -66,5 +56,3 @@
 #endif
     return 0;
 }
-
-#endif /* HAVE_SCHED_H */
diff --git a/libcutils/klog.c b/libcutils/klog.c
index d69fb10..fbb7b72 100644
--- a/libcutils/klog.c
+++ b/libcutils/klog.c
@@ -28,6 +28,10 @@
 static int klog_fd = -1;
 static int klog_level = KLOG_DEFAULT_LEVEL;
 
+int klog_get_level(void) {
+    return klog_level;
+}
+
 void klog_set_level(int level) {
     klog_level = level;
 }
@@ -49,18 +53,24 @@
 
 #define LOG_BUF_MAX 512
 
-void klog_write(int level, const char *fmt, ...)
+void klog_vwrite(int level, const char *fmt, va_list ap)
 {
     char buf[LOG_BUF_MAX];
-    va_list ap;
 
     if (level > klog_level) return;
     if (klog_fd < 0) klog_init();
     if (klog_fd < 0) return;
 
-    va_start(ap, fmt);
     vsnprintf(buf, LOG_BUF_MAX, fmt, ap);
     buf[LOG_BUF_MAX - 1] = 0;
-    va_end(ap);
+
     write(klog_fd, buf, strlen(buf));
 }
+
+void klog_write(int level, const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    klog_vwrite(level, fmt, ap);
+    va_end(ap);
+}
diff --git a/libcutils/partition_utils.c b/libcutils/partition_utils.c
index 10539fa..823b162 100644
--- a/libcutils/partition_utils.c
+++ b/libcutils/partition_utils.c
@@ -14,12 +14,13 @@
  * limitations under the License.
  */
 
-#include <sys/types.h>
-#include <unistd.h>
 #include <fcntl.h>
-#include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <sys/mount.h> /* for BLKGETSIZE */
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
 #include <cutils/properties.h>
 
 static int only_one_char(char *buf, int len, char c)
@@ -39,7 +40,7 @@
 int partition_wiped(char *source)
 {
     char buf[4096];
-    int fd, ret, wiped;
+    int fd, ret;
 
     if ((fd = open(source, O_RDONLY)) < 0) {
         return 0;
diff --git a/libcutils/process_name.c b/libcutils/process_name.c
index a6ab951..9c3dfb8 100644
--- a/libcutils/process_name.c
+++ b/libcutils/process_name.c
@@ -14,25 +14,27 @@
  * limitations under the License.
  */
 
+#include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
+#if defined(HAVE_PRCTL)
+#include <sys/prctl.h>
+#endif
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
 #include <cutils/process_name.h>
 #ifdef HAVE_ANDROID_OS
 #include <cutils/properties.h>
 #endif
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#if defined(HAVE_PRCTL)
-#include <sys/prctl.h>
-#endif
 
 #define PROCESS_NAME_DEVICE "/sys/qemu_trace/process_name"
 
 static const char* process_name = "unknown";
+#ifdef HAVE_ANDROID_OS
 static int running_in_emulator = -1;
+#endif
 
 void set_process_name(const char* new_name) {
 #ifdef HAVE_ANDROID_OS
diff --git a/libcutils/properties.c b/libcutils/properties.c
index 28d8b2f..b283658 100644
--- a/libcutils/properties.c
+++ b/libcutils/properties.c
@@ -15,17 +15,95 @@
  */
 
 #define LOG_TAG "properties"
+// #define LOG_NDEBUG 0
 
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 #include <unistd.h>
 #include <cutils/sockets.h>
 #include <errno.h>
 #include <assert.h>
 
 #include <cutils/properties.h>
+#include <stdbool.h>
+#include <inttypes.h>
 #include "loghack.h"
 
+int8_t property_get_bool(const char *key, int8_t default_value) {
+    if (!key) {
+        return default_value;
+    }
+
+    int8_t result = default_value;
+    char buf[PROPERTY_VALUE_MAX] = {'\0',};
+
+    int len = property_get(key, buf, "");
+    if (len == 1) {
+        char ch = buf[0];
+        if (ch == '0' || ch == 'n') {
+            result = false;
+        } else if (ch == '1' || ch == 'y') {
+            result = true;
+        }
+    } else if (len > 1) {
+         if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
+            result = false;
+        } else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) {
+            result = true;
+        }
+    }
+
+    return result;
+}
+
+// Convert string property to int (default if fails); return default value if out of bounds
+static intmax_t property_get_imax(const char *key, intmax_t lower_bound, intmax_t upper_bound,
+        intmax_t default_value) {
+    if (!key) {
+        return default_value;
+    }
+
+    intmax_t result = default_value;
+    char buf[PROPERTY_VALUE_MAX] = {'\0',};
+    char *end = NULL;
+
+    int len = property_get(key, buf, "");
+    if (len > 0) {
+        int tmp = errno;
+        errno = 0;
+
+        // Infer base automatically
+        result = strtoimax(buf, &end, /*base*/0);
+        if ((result == INTMAX_MIN || result == INTMAX_MAX) && errno == ERANGE) {
+            // Over or underflow
+            result = default_value;
+            ALOGV("%s(%s,%" PRIdMAX ") - overflow", __FUNCTION__, key, default_value);
+        } else if (result < lower_bound || result > upper_bound) {
+            // Out of range of requested bounds
+            result = default_value;
+            ALOGV("%s(%s,%" PRIdMAX ") - out of range", __FUNCTION__, key, default_value);
+        } else if (end == buf) {
+            // Numeric conversion failed
+            result = default_value;
+            ALOGV("%s(%s,%" PRIdMAX ") - numeric conversion failed",
+                    __FUNCTION__, key, default_value);
+        }
+
+        errno = tmp;
+    }
+
+    return result;
+}
+
+int64_t property_get_int64(const char *key, int64_t default_value) {
+    return (int64_t)property_get_imax(key, INT64_MIN, INT64_MAX, default_value);
+}
+
+int32_t property_get_int32(const char *key, int32_t default_value) {
+    return (int32_t)property_get_imax(key, INT32_MIN, INT32_MAX, default_value);
+}
+
 #ifdef HAVE_LIBC_SYSTEM_PROPERTIES
 
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
@@ -44,10 +122,13 @@
     if(len > 0) {
         return len;
     }
-    
     if(default_value) {
         len = strlen(default_value);
-        memcpy(value, default_value, len + 1);
+        if (len >= PROPERTY_VALUE_MAX) {
+            len = PROPERTY_VALUE_MAX - 1;
+        }
+        memcpy(value, default_value, len);
+        value[len] = '\0';
     }
     return len;
 }
diff --git a/libcutils/qtaguid.c b/libcutils/qtaguid.c
index 5bb8176..00e211c 100644
--- a/libcutils/qtaguid.c
+++ b/libcutils/qtaguid.c
@@ -1,5 +1,4 @@
-/* libcutils/qtaguid.c
-**
+/*
 ** Copyright 2011, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,14 +18,16 @@
 
 #define LOG_TAG "qtaguid"
 
-#include <cutils/qtaguid.h>
-#include <cutils/log.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
+#include <pthread.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
-#include <pthread.h>
+
+#include <cutils/qtaguid.h>
+#include <log/log.h>
 
 static const char* CTRL_PROCPATH = "/proc/net/xt_qtaguid/ctrl";
 static const int CTRL_MAX_INPUT_LEN = 128;
@@ -103,13 +104,13 @@
 
     pthread_once(&resTrackInitDone, qtaguid_resTrack);
 
-    snprintf(lineBuf, sizeof(lineBuf), "t %d %llu %d", sockfd, kTag, uid);
+    snprintf(lineBuf, sizeof(lineBuf), "t %d %" PRIu64 " %d", sockfd, kTag, uid);
 
-    ALOGV("Tagging socket %d with tag %llx{%u,0} for uid %d", sockfd, kTag, tag, uid);
+    ALOGV("Tagging socket %d with tag %" PRIx64 "{%u,0} for uid %d", sockfd, kTag, tag, uid);
 
     res = write_ctrl(lineBuf);
     if (res < 0) {
-        ALOGI("Tagging socket %d with tag %llx(%d) for uid %d failed errno=%d",
+        ALOGI("Tagging socket %d with tag %" PRIx64 "(%d) for uid %d failed errno=%d",
              sockfd, kTag, tag, uid, res);
     }
 
@@ -144,17 +145,17 @@
 
 int qtaguid_deleteTagData(int tag, uid_t uid) {
     char lineBuf[CTRL_MAX_INPUT_LEN];
-    int fd, cnt = 0, res = 0;
+    int cnt = 0, res = 0;
     uint64_t kTag = (uint64_t)tag << 32;
 
-    ALOGV("Deleting tag data with tag %llx{%d,0} for uid %d", kTag, tag, uid);
+    ALOGV("Deleting tag data with tag %" PRIx64 "{%d,0} for uid %d", kTag, tag, uid);
 
     pthread_once(&resTrackInitDone, qtaguid_resTrack);
 
-    snprintf(lineBuf, sizeof(lineBuf), "d %llu %d", kTag, uid);
+    snprintf(lineBuf, sizeof(lineBuf), "d %" PRIu64 " %d", kTag, uid);
     res = write_ctrl(lineBuf);
     if (res < 0) {
-        ALOGI("Deleteing tag data with tag %llx/%d for uid %d failed with cnt=%d errno=%d",
+        ALOGI("Deleting tag data with tag %" PRIx64 "/%d for uid %d failed with cnt=%d errno=%d",
              kTag, tag, uid, cnt, errno);
     }
 
@@ -162,8 +163,6 @@
 }
 
 int qtaguid_setPacifier(int on) {
-    int param_fd;
-    int res;
     const char *value;
 
     value = on ? "Y" : "N";
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index d20d217..9f092d6 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -1,6 +1,4 @@
-
-/* libs/cutils/sched_policy.c
-**
+/*
 ** Copyright 2007, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License"); 
@@ -18,14 +16,17 @@
 
 #define LOG_TAG "SchedPolicy"
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
 #include <cutils/sched_policy.h>
-#include <cutils/log.h>
+#include <log/log.h>
+
+#define UNUSED __attribute__((__unused__))
 
 /* Re-map SP_DEFAULT to the system default policy, and leave other values unchanged.
  * Call this any place a SchedPolicy is used as an input parameter.
@@ -331,12 +332,12 @@
 
 /* Stubs for non-Android targets. */
 
-int set_sched_policy(int tid, SchedPolicy policy)
+int set_sched_policy(int tid UNUSED, SchedPolicy policy UNUSED)
 {
     return 0;
 }
 
-int get_sched_policy(int tid, SchedPolicy *policy)
+int get_sched_policy(int tid UNUSED, SchedPolicy *policy)
 {
     *policy = SP_SYSTEM_DEFAULT;
     return 0;
diff --git a/libcutils/socket_inaddr_any_server.c b/libcutils/socket_inaddr_any_server.c
index 7d5dab4..6c849de 100644
--- a/libcutils/socket_inaddr_any_server.c
+++ b/libcutils/socket_inaddr_any_server.c
@@ -1,5 +1,4 @@
-/* libs/cutils/socket_inaddr_any_server.c
-**
+/*
 ** Copyright 2006, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License"); 
@@ -15,13 +14,11 @@
 ** limitations under the License.
 */
 
-#include <cutils/sockets.h>
-
+#include <errno.h>
+#include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <errno.h>
-#include <stddef.h>
 
 #ifndef HAVE_WINSOCK
 #include <sys/socket.h>
@@ -30,13 +27,14 @@
 #include <netinet/in.h>
 #endif
 
+#include <cutils/sockets.h>
+
 #define LISTEN_BACKLOG 4
 
 /* open listen() port on any interface */
 int socket_inaddr_any_server(int port, int type)
 {
     struct sockaddr_in addr;
-    size_t alen;
     int s, n;
 
     memset(&addr, 0, sizeof(addr));
@@ -48,7 +46,7 @@
     if(s < 0) return -1;
 
     n = 1;
-    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
+    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *) &n, sizeof(n));
 
     if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
         close(s);
diff --git a/libcutils/socket_local_client.c b/libcutils/socket_local_client.c
index 5310516..ddcc2da 100644
--- a/libcutils/socket_local_client.c
+++ b/libcutils/socket_local_client.c
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-#include <cutils/sockets.h>
-
+#include <errno.h>
+#include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <errno.h>
-#include <stddef.h>
+
+#include <cutils/sockets.h>
 
 #ifdef HAVE_WINSOCK
 
@@ -128,7 +128,6 @@
 {
     struct sockaddr_un addr;
     socklen_t alen;
-    size_t namelen;
     int err;
 
     err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
diff --git a/libcutils/socket_local_server.c b/libcutils/socket_local_server.c
index 4971b1b..7628fe4 100644
--- a/libcutils/socket_local_server.c
+++ b/libcutils/socket_local_server.c
@@ -43,6 +43,8 @@
 
 #define LISTEN_BACKLOG 4
 
+/* Only the bottom bits are really the socket type; there are flags too. */
+#define SOCK_TYPE_MASK 0xf
 
 /**
  * Binds a pre-created socket(AF_LOCAL) 's' to 'name'
@@ -107,7 +109,7 @@
         return -1;
     }
 
-    if (type == SOCK_STREAM) {
+    if ((type & SOCK_TYPE_MASK) == SOCK_STREAM) {
         int ret;
 
         ret = listen(s, LISTEN_BACKLOG);
diff --git a/libcutils/socket_loopback_client.c b/libcutils/socket_loopback_client.c
index cb82c5e..9aed7b7 100644
--- a/libcutils/socket_loopback_client.c
+++ b/libcutils/socket_loopback_client.c
@@ -1,5 +1,4 @@
-/* libs/cutils/socket_loopback_client.c
-**
+/*
 ** Copyright 2006, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License"); 
@@ -15,13 +14,11 @@
 ** limitations under the License.
 */
 
-#include <cutils/sockets.h>
-
+#include <errno.h>
+#include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <errno.h>
-#include <stddef.h>
 
 #ifndef HAVE_WINSOCK
 #include <sys/socket.h>
@@ -30,6 +27,8 @@
 #include <netinet/in.h>
 #endif
 
+#include <cutils/sockets.h>
+
 /* Connect to port on the loopback IP interface. type is
  * SOCK_STREAM or SOCK_DGRAM. 
  * return is a file descriptor or -1 on error
@@ -37,7 +36,6 @@
 int socket_loopback_client(int port, int type)
 {
     struct sockaddr_in addr;
-    socklen_t alen;
     int s;
 
     memset(&addr, 0, sizeof(addr));
diff --git a/libcutils/socket_loopback_server.c b/libcutils/socket_loopback_server.c
index 3208488..71afce7 100644
--- a/libcutils/socket_loopback_server.c
+++ b/libcutils/socket_loopback_server.c
@@ -1,5 +1,4 @@
-/* libs/cutils/socket_loopback_server.c
-**
+/*
 ** Copyright 2006, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License"); 
@@ -15,13 +14,11 @@
 ** limitations under the License.
 */
 
-#include <cutils/sockets.h>
-
+#include <errno.h>
+#include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <errno.h>
-#include <stddef.h>
 
 #define LISTEN_BACKLOG 4
 
@@ -32,11 +29,12 @@
 #include <netinet/in.h>
 #endif
 
+#include <cutils/sockets.h>
+
 /* open listen() port on loopback interface */
 int socket_loopback_server(int port, int type)
 {
     struct sockaddr_in addr;
-    size_t alen;
     int s, n;
 
     memset(&addr, 0, sizeof(addr));
@@ -48,7 +46,7 @@
     if(s < 0) return -1;
 
     n = 1;
-    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
+    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *) &n, sizeof(n));
 
     if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
         close(s);
diff --git a/libcutils/socket_network_client.c b/libcutils/socket_network_client.c
index a64006c..4826033 100644
--- a/libcutils/socket_network_client.c
+++ b/libcutils/socket_network_client.c
@@ -1,5 +1,4 @@
-/* libs/cutils/socket_network_client.c
-**
+/*
 ** Copyright 2006, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License"); 
@@ -15,22 +14,20 @@
 ** limitations under the License.
 */
 
-#include <cutils/sockets.h>
-
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <errno.h>
-#include <stddef.h>
 
-#ifndef HAVE_WINSOCK
 #include <sys/socket.h>
 #include <sys/select.h>
 #include <sys/types.h>
 #include <netinet/in.h>
 #include <netdb.h>
-#endif
 
+#include <cutils/sockets.h>
 
 /* Connect to port on the IP interface. type is
  * SOCK_STREAM or SOCK_DGRAM. 
@@ -38,28 +35,92 @@
  */
 int socket_network_client(const char *host, int port, int type)
 {
+    return socket_network_client_timeout(host, port, type, 0);
+}
+
+/* Connect to port on the IP interface. type is SOCK_STREAM or SOCK_DGRAM.
+ * timeout in seconds return is a file descriptor or -1 on error
+ */
+int socket_network_client_timeout(const char *host, int port, int type, int timeout)
+{
     struct hostent *hp;
     struct sockaddr_in addr;
     socklen_t alen;
     int s;
+    int flags = 0, error = 0, ret = 0;
+    fd_set rset, wset;
+    socklen_t len = sizeof(error);
+    struct timeval ts;
+
+    ts.tv_sec = timeout;
+    ts.tv_usec = 0;
 
     hp = gethostbyname(host);
-    if(hp == 0) return -1;
-    
+    if (hp == 0) return -1;
+
     memset(&addr, 0, sizeof(addr));
     addr.sin_family = hp->h_addrtype;
     addr.sin_port = htons(port);
     memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
 
     s = socket(hp->h_addrtype, type, 0);
-    if(s < 0) return -1;
+    if (s < 0) return -1;
 
-    if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+    if ((flags = fcntl(s, F_GETFL, 0)) < 0) {
+        close(s);
+        return -1;
+    }
+
+    if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
+        close(s);
+        return -1;
+    }
+
+    if ((ret = connect(s, (struct sockaddr *) &addr, sizeof(addr))) < 0) {
+        if (errno != EINPROGRESS) {
+            close(s);
+            return -1;
+        }
+    }
+
+    if (ret == 0)
+        goto done;
+
+    FD_ZERO(&rset);
+    FD_SET(s, &rset);
+    wset = rset;
+
+    if ((ret = select(s + 1, &rset, &wset, NULL, (timeout) ? &ts : NULL)) < 0) {
+        close(s);
+        return -1;
+    }
+    if (ret == 0) {   // we had a timeout
+        errno = ETIMEDOUT;
+        close(s);
+        return -1;
+    }
+
+    if (FD_ISSET(s, &rset) || FD_ISSET(s, &wset)) {
+        if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
+            close(s);
+            return -1;
+        }
+    } else {
+        close(s);
+        return -1;
+    }
+
+    if (error) {  // check if we had a socket error
+        errno = error;
+        close(s);
+        return -1;
+    }
+
+done:
+    if (fcntl(s, F_SETFL, flags) < 0) {
         close(s);
         return -1;
     }
 
     return s;
-
 }
-
diff --git a/libcutils/sockets.c b/libcutils/sockets.c
index b5a1b3d..15ede2b 100644
--- a/libcutils/sockets.c
+++ b/libcutils/sockets.c
@@ -14,15 +14,18 @@
  * limitations under the License.
  */
 
-#include <cutils/log.h>
 #include <cutils/sockets.h>
+#include <log/log.h>
 
 #ifdef HAVE_ANDROID_OS
 /* For the socket trust (credentials) check */
 #include <private/android_filesystem_config.h>
+#define __android_unused
+#else
+#define __android_unused __attribute__((__unused__))
 #endif
 
-bool socket_peer_is_trusted(int fd)
+bool socket_peer_is_trusted(int fd __android_unused)
 {
 #ifdef HAVE_ANDROID_OS
     struct ucred cr;
diff --git a/libcutils/str_parms.c b/libcutils/str_parms.c
index 7cfbcb3..2e3ce9f 100644
--- a/libcutils/str_parms.c
+++ b/libcutils/str_parms.c
@@ -25,10 +25,9 @@
 #include <string.h>
 
 #include <cutils/hashmap.h>
-#include <cutils/log.h>
 #include <cutils/memory.h>
-
 #include <cutils/str_parms.h>
+#include <log/log.h>
 
 #define UNUSED __attribute__((unused))
 
@@ -194,23 +193,46 @@
 int str_parms_add_str(struct str_parms *str_parms, const char *key,
                       const char *value)
 {
-    void *old_val;
-    void *tmp_key;
-    void *tmp_val;
+    void *tmp_key = NULL;
+    void *tmp_val = NULL;
+    void *old_val = NULL;
+
+    // strdup and hashmapPut both set errno on failure.
+    // Set errno to 0 so we can recognize whether anything went wrong.
+    int saved_errno = errno;
+    errno = 0;
 
     tmp_key = strdup(key);
-    tmp_val = strdup(value);
-    old_val = hashmapPut(str_parms->map, tmp_key, tmp_val);
-
-    if (old_val) {
-        free(old_val);
-        free(tmp_key);
-    } else if (errno == ENOMEM) {
-        free(tmp_key);
-        free(tmp_val);
-        return -ENOMEM;
+    if (tmp_key == NULL) {
+        goto clean_up;
     }
-    return 0;
+
+    tmp_val = strdup(value);
+    if (tmp_val == NULL) {
+        goto clean_up;
+    }
+
+    old_val = hashmapPut(str_parms->map, tmp_key, tmp_val);
+    if (old_val == NULL) {
+        // Did hashmapPut fail?
+        if (errno == ENOMEM) {
+            goto clean_up;
+        }
+        // For new keys, hashmap takes ownership of tmp_key and tmp_val.
+        tmp_key = tmp_val = NULL;
+    } else {
+        // For existing keys, hashmap takes ownership of tmp_val.
+        // (It also gives up ownership of old_val.)
+        tmp_val = NULL;
+    }
+
+clean_up:
+    free(tmp_key);
+    free(tmp_val);
+    free(old_val);
+    int result = -errno;
+    errno = saved_errno;
+    return result;
 }
 
 int str_parms_add_int(struct str_parms *str_parms, const char *key, int value)
@@ -337,7 +359,6 @@
 {
     struct str_parms *str_parms;
     char *out_str;
-    int ret;
 
     str_parms = str_parms_create_str(str);
     str_parms_add_str(str_parms, "dude", "woah");
@@ -352,8 +373,6 @@
 
 int main(void)
 {
-    struct str_parms *str_parms;
-
     test_str_parms_str("");
     test_str_parms_str(";");
     test_str_parms_str("=");
@@ -370,6 +389,15 @@
     test_str_parms_str("foo=bar;baz=bat;");
     test_str_parms_str("foo=bar;baz=bat;foo=bar");
 
+    // hashmapPut reports errors by setting errno to ENOMEM.
+    // Test that we're not confused by running in an environment where this is already true.
+    errno = ENOMEM;
+    test_str_parms_str("foo=bar;baz=");
+    if (errno != ENOMEM) {
+        abort();
+    }
+    test_str_parms_str("foo=bar;baz=");
+
     return 0;
 }
 #endif
diff --git a/libcutils/tests/Android.mk b/libcutils/tests/Android.mk
index 6571161..8e65310 100644
--- a/libcutils/tests/Android.mk
+++ b/libcutils/tests/Android.mk
@@ -1 +1,48 @@
-include $(all-subdir-makefiles)
+# Copyright (C) 2014 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.
+
+LOCAL_PATH := $(call my-dir)
+
+test_src_files := \
+    MemsetTest.cpp \
+    PropertiesTest.cpp \
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcutils_test
+LOCAL_SRC_FILES := $(test_src_files)
+LOCAL_SHARED_LIBRARIES := \
+    libcutils \
+    liblog \
+    libutils \
+
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcutils_test_static
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_SRC_FILES := $(test_src_files)
+LOCAL_STATIC_LIBRARIES := \
+    libc \
+    libcutils \
+    liblog \
+    libstlport_static \
+    libutils \
+
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+include $(BUILD_NATIVE_TEST)
diff --git a/libcutils/tests/MemsetTest.cpp b/libcutils/tests/MemsetTest.cpp
new file mode 100644
index 0000000..45efc51
--- /dev/null
+++ b/libcutils/tests/MemsetTest.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2014 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <cutils/memory.h>
+#include <gtest/gtest.h>
+
+#define FENCEPOST_LENGTH 8
+
+#define MAX_TEST_SIZE (64*1024)
+// Choose values that have no repeating byte values.
+#define MEMSET16_PATTERN 0xb139
+#define MEMSET32_PATTERN 0x48193a27
+
+enum test_e {
+  MEMSET16 = 0,
+  MEMSET32,
+};
+
+static int g_memset16_aligns[][2] = {
+  { 2, 0 },
+  { 4, 0 },
+  { 8, 0 },
+  { 16, 0 },
+  { 32, 0 },
+  { 64, 0 },
+  { 128, 0 },
+
+  { 4, 2 },
+
+  { 8, 2 },
+  { 8, 4 },
+  { 8, 6 },
+
+  { 128, 2 },
+  { 128, 4 },
+  { 128, 6 },
+  { 128, 8 },
+  { 128, 10 },
+  { 128, 12 },
+  { 128, 14 },
+  { 128, 16 },
+};
+
+static int g_memset32_aligns[][2] = {
+  { 4, 0 },
+  { 8, 0 },
+  { 16, 0 },
+  { 32, 0 },
+  { 64, 0 },
+  { 128, 0 },
+
+  { 8, 4 },
+
+  { 128, 4 },
+  { 128, 8 },
+  { 128, 12 },
+  { 128, 16 },
+};
+
+static size_t GetIncrement(size_t len, size_t min_incr) {
+  if (len >= 4096) {
+    return 1024;
+  } else if (len >= 1024) {
+    return 256;
+  }
+  return min_incr;
+}
+
+// Return a pointer into the current buffer with the specified alignment.
+static void *GetAlignedPtr(void *orig_ptr, int alignment, int or_mask) {
+  uint64_t ptr = reinterpret_cast<uint64_t>(orig_ptr);
+  if (alignment > 0) {
+      // When setting the alignment, set it to exactly the alignment chosen.
+      // The pointer returned will be guaranteed not to be aligned to anything
+      // more than that.
+      ptr += alignment - (ptr & (alignment - 1));
+      ptr |= alignment | or_mask;
+  }
+
+  return reinterpret_cast<void*>(ptr);
+}
+
+static void SetFencepost(uint8_t *buffer) {
+  for (int i = 0; i < FENCEPOST_LENGTH; i += 2) {
+    buffer[i] = 0xde;
+    buffer[i+1] = 0xad;
+  }
+}
+
+static void VerifyFencepost(uint8_t *buffer) {
+  for (int i = 0; i < FENCEPOST_LENGTH; i += 2) {
+    if (buffer[i] != 0xde || buffer[i+1] != 0xad) {
+      uint8_t expected_value;
+      if (buffer[i] == 0xde) {
+        i++;
+        expected_value = 0xad;
+      } else {
+        expected_value = 0xde;
+      }
+      ASSERT_EQ(expected_value, buffer[i]);
+    }
+  }
+}
+
+void RunMemsetTests(test_e test_type, uint32_t value, int align[][2], size_t num_aligns) {
+  size_t min_incr = 4;
+  if (test_type == MEMSET16) {
+    min_incr = 2;
+    value |= value << 16;
+  }
+  uint32_t* expected_buf = new uint32_t[MAX_TEST_SIZE/sizeof(uint32_t)];
+  for (size_t i = 0; i < MAX_TEST_SIZE/sizeof(uint32_t); i++) {
+    expected_buf[i] = value;
+  }
+
+  // Allocate one large buffer with lots of extra space so that we can
+  // guarantee that all possible alignments will fit.
+  uint8_t *buf = new uint8_t[3*MAX_TEST_SIZE];
+  uint8_t *buf_align;
+  for (size_t i = 0; i < num_aligns; i++) {
+    size_t incr = min_incr;
+    for (size_t len = incr; len <= MAX_TEST_SIZE; len += incr) {
+      incr = GetIncrement(len, min_incr);
+
+      buf_align = reinterpret_cast<uint8_t*>(GetAlignedPtr(
+          buf+FENCEPOST_LENGTH, align[i][0], align[i][1]));
+
+      SetFencepost(&buf_align[-FENCEPOST_LENGTH]);
+      SetFencepost(&buf_align[len]);
+
+      memset(buf_align, 0xff, len);
+      if (test_type == MEMSET16) {
+        android_memset16(reinterpret_cast<uint16_t*>(buf_align), value, len);
+      } else {
+        android_memset32(reinterpret_cast<uint32_t*>(buf_align), value, len);
+      }
+      ASSERT_EQ(0, memcmp(expected_buf, buf_align, len))
+          << "Failed size " << len << " align " << align[i][0] << " " << align[i][1] << "\n";
+
+      VerifyFencepost(&buf_align[-FENCEPOST_LENGTH]);
+      VerifyFencepost(&buf_align[len]);
+    }
+  }
+  delete expected_buf;
+  delete buf;
+}
+
+TEST(libcutils, android_memset16_non_zero) {
+  RunMemsetTests(MEMSET16, MEMSET16_PATTERN, g_memset16_aligns, sizeof(g_memset16_aligns)/sizeof(int[2]));
+}
+
+TEST(libcutils, android_memset16_zero) {
+  RunMemsetTests(MEMSET16, 0, g_memset16_aligns, sizeof(g_memset16_aligns)/sizeof(int[2]));
+}
+
+TEST(libcutils, android_memset32_non_zero) {
+  RunMemsetTests(MEMSET32, MEMSET32_PATTERN, g_memset32_aligns, sizeof(g_memset32_aligns)/sizeof(int[2]));
+}
+
+TEST(libcutils, android_memset32_zero) {
+  RunMemsetTests(MEMSET32, 0, g_memset32_aligns, sizeof(g_memset32_aligns)/sizeof(int[2]));
+}
diff --git a/libcutils/tests/PropertiesTest.cpp b/libcutils/tests/PropertiesTest.cpp
new file mode 100644
index 0000000..659821c
--- /dev/null
+++ b/libcutils/tests/PropertiesTest.cpp
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2014 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 "Properties_test"
+#include <utils/Log.h>
+#include <gtest/gtest.h>
+
+#include <cutils/properties.h>
+#include <limits.h>
+#include <string>
+#include <sstream>
+#include <iostream>
+
+namespace android {
+
+#define STRINGIFY_INNER(x) #x
+#define STRINGIFY(x) STRINGIFY_INNER(x)
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+#define ASSERT_OK(x) ASSERT_EQ(0, (x))
+#define EXPECT_OK(x) EXPECT_EQ(0, (x))
+
+#define PROPERTY_TEST_KEY "libcutils.test.key"
+#define PROPERTY_TEST_VALUE_DEFAULT "<<<default_value>>>"
+
+template <typename T>
+static std::string HexString(T value) {
+    std::stringstream ss;
+    ss << "0x" << std::hex << std::uppercase << value;
+    return ss.str();
+}
+
+template <typename T>
+static ::testing::AssertionResult AssertEqualHex(const char *mExpr,
+        const char *nExpr,
+        T m,
+        T n) {
+    if (m == n) {
+        return ::testing::AssertionSuccess();
+    }
+
+    return ::testing::AssertionFailure()
+        << mExpr << " and " << nExpr << " (expected: " << HexString(m) <<
+        ", actual: " << HexString(n) << ") are not equal";
+}
+
+class PropertiesTest : public testing::Test {
+public:
+    PropertiesTest() : mValue() {}
+protected:
+    virtual void SetUp() {
+        EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL));
+    }
+
+    virtual void TearDown() {
+        EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL));
+    }
+
+    char mValue[PROPERTY_VALUE_MAX];
+
+    template <typename T>
+    static std::string ToString(T value) {
+        std::stringstream ss;
+        ss << value;
+
+        return ss.str();
+    }
+
+    // Return length of property read; value is written into mValue
+    int SetAndGetProperty(const char* value, const char* defaultValue = PROPERTY_TEST_VALUE_DEFAULT) {
+        EXPECT_OK(property_set(PROPERTY_TEST_KEY, value)) << "value: '" << value << "'";
+        return property_get(PROPERTY_TEST_KEY, mValue, defaultValue);
+    }
+
+    void ResetValue(unsigned char c = 0xFF) {
+        for (size_t i = 0; i < ARRAY_SIZE(mValue); ++i) {
+            mValue[i] = (char) c;
+        }
+    }
+};
+
+TEST_F(PropertiesTest, SetString) {
+
+    // Null key -> unsuccessful set
+    {
+        // Null key -> fails
+        EXPECT_GT(0, property_set(/*key*/NULL, PROPERTY_TEST_VALUE_DEFAULT));
+    }
+
+    // Null value -> returns default value
+    {
+        // Null value -> OK , and it clears the value
+        EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL));
+        ResetValue();
+
+        // Since the value is null, default value will be returned
+        int len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
+        EXPECT_EQ(strlen(PROPERTY_TEST_VALUE_DEFAULT), len);
+        EXPECT_STREQ(PROPERTY_TEST_VALUE_DEFAULT, mValue);
+    }
+
+    // Trivial case => get returns what was set
+    {
+        int len = SetAndGetProperty("hello_world");
+        EXPECT_EQ(strlen("hello_world"), len) << "hello_world key";
+        EXPECT_STREQ("hello_world", mValue);
+        ResetValue();
+    }
+
+    // Set to empty string => get returns default always
+    {
+        const char* EMPTY_STRING_DEFAULT = "EMPTY_STRING";
+        int len = SetAndGetProperty("", EMPTY_STRING_DEFAULT);
+        EXPECT_EQ(strlen(EMPTY_STRING_DEFAULT), len) << "empty key";
+        EXPECT_STREQ(EMPTY_STRING_DEFAULT, mValue);
+        ResetValue();
+    }
+
+    // Set to max length => get returns what was set
+    {
+        std::string maxLengthString = std::string(PROPERTY_VALUE_MAX-1, 'a');
+
+        int len = SetAndGetProperty(maxLengthString.c_str());
+        EXPECT_EQ(PROPERTY_VALUE_MAX-1, len) << "max length key";
+        EXPECT_STREQ(maxLengthString.c_str(), mValue);
+        ResetValue();
+    }
+
+    // Set to max length + 1 => set fails
+    {
+        const char* VALID_TEST_VALUE = "VALID_VALUE";
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, VALID_TEST_VALUE));
+
+        std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a');
+
+        // Expect that the value set fails since it's too long
+        EXPECT_GT(0, property_set(PROPERTY_TEST_KEY, oneLongerString.c_str()));
+        int len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
+
+        EXPECT_EQ(strlen(VALID_TEST_VALUE), len) << "set should've failed";
+        EXPECT_STREQ(VALID_TEST_VALUE, mValue);
+        ResetValue();
+    }
+}
+
+TEST_F(PropertiesTest, GetString) {
+
+    // Try to use a default value that's too long => set fails
+    {
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
+
+        std::string maxLengthString = std::string(PROPERTY_VALUE_MAX-1, 'a');
+        std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a');
+
+        // Expect that the value is truncated since it's too long (by 1)
+        int len = property_get(PROPERTY_TEST_KEY, mValue, oneLongerString.c_str());
+        EXPECT_EQ(PROPERTY_VALUE_MAX-1, len);
+        EXPECT_STREQ(maxLengthString.c_str(), mValue);
+        ResetValue();
+    }
+}
+
+TEST_F(PropertiesTest, GetBool) {
+    /**
+     * TRUE
+     */
+    const char *valuesTrue[] = { "1", "true", "y", "yes", "on", };
+    for (size_t i = 0; i < ARRAY_SIZE(valuesTrue); ++i) {
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesTrue[i]));
+        bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/false);
+        EXPECT_TRUE(val) << "Property should've been TRUE for value: '" << valuesTrue[i] << "'";
+    }
+
+    /**
+     * FALSE
+     */
+    const char *valuesFalse[] = { "0", "false", "n", "no", "off", };
+    for (size_t i = 0; i < ARRAY_SIZE(valuesFalse); ++i) {
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesFalse[i]));
+        bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/true);
+        EXPECT_FALSE(val) << "Property shoud've been FALSE For string value: '" << valuesFalse[i] << "'";
+    }
+
+    /**
+     * NEITHER
+     */
+    const char *valuesNeither[] = { "x0", "x1", "2", "-2", "True", "False", "garbage", "", " ",
+            "+1", "  1  ", "  true", "  true  ", "  y  ", "  yes", "yes  ",
+            "+0", "-0", "00", "  00  ", "  false", "false  ",
+    };
+    for (size_t i = 0; i < ARRAY_SIZE(valuesNeither); ++i) {
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesNeither[i]));
+
+        // The default value should always be used
+        bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/true);
+        EXPECT_TRUE(val) << "Property should've been NEITHER (true) for string value: '" << valuesNeither[i] << "'";
+
+        val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/false);
+        EXPECT_FALSE(val) << "Property should've been NEITHER (false) for string value: '" << valuesNeither[i] << "'";
+    }
+}
+
+TEST_F(PropertiesTest, GetInt64) {
+    const int64_t DEFAULT_VALUE = INT64_C(0xDEADBEEFBEEFDEAD);
+
+    const std::string longMaxString = ToString(INT64_MAX);
+    const std::string longStringOverflow = longMaxString + "0";
+
+    const std::string longMinString = ToString(INT64_MIN);
+    const std::string longStringUnderflow = longMinString + "0";
+
+    const char* setValues[] = {
+        // base 10
+        "1", "2", "12345", "-1", "-2", "-12345",
+        // base 16
+        "0xFF", "0x0FF", "0xC0FFEE",
+        // base 8
+        "0", "01234", "07",
+        // corner cases
+        "       2", "2      ", "+0", "-0", "  +0   ", longMaxString.c_str(), longMinString.c_str(),
+        // failing cases
+        NULL, "", " ", "    ", "hello", "     true     ", "y",
+        longStringOverflow.c_str(), longStringUnderflow.c_str(),
+    };
+
+    int64_t getValues[] = {
+        // base 10
+        1, 2, 12345, -1, -2, -12345,
+        // base 16
+        0xFF, 0x0FF, 0xC0FFEE,
+        // base 8
+        0, 01234, 07,
+        // corner cases
+        2, 2, 0, 0, 0, INT64_MAX, INT64_MIN,
+        // failing cases
+        DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE,
+        DEFAULT_VALUE, DEFAULT_VALUE,
+    };
+
+    ASSERT_EQ(ARRAY_SIZE(setValues), ARRAY_SIZE(getValues));
+
+    for (size_t i = 0; i < ARRAY_SIZE(setValues); ++i) {
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, setValues[i]));
+
+        int64_t val = property_get_int64(PROPERTY_TEST_KEY, DEFAULT_VALUE);
+        EXPECT_PRED_FORMAT2(AssertEqualHex, getValues[i], val) << "Property was set to '" << setValues[i] << "'";
+    }
+}
+
+TEST_F(PropertiesTest, GetInt32) {
+    const int32_t DEFAULT_VALUE = INT32_C(0xDEADBEEF);
+
+    const std::string intMaxString = ToString(INT32_MAX);
+    const std::string intStringOverflow = intMaxString + "0";
+
+    const std::string intMinString = ToString(INT32_MIN);
+    const std::string intStringUnderflow = intMinString + "0";
+
+    const char* setValues[] = {
+        // base 10
+        "1", "2", "12345", "-1", "-2", "-12345",
+        // base 16
+        "0xFF", "0x0FF", "0xC0FFEE", "0Xf00",
+        // base 8
+        "0", "01234", "07",
+        // corner cases
+        "       2", "2      ", "+0", "-0", "  +0   ", intMaxString.c_str(), intMinString.c_str(),
+        // failing cases
+        NULL, "", " ", "    ", "hello", "     true     ", "y",
+        intStringOverflow.c_str(), intStringUnderflow.c_str(),
+    };
+
+    int32_t getValues[] = {
+        // base 10
+        1, 2, 12345, -1, -2, -12345,
+        // base 16
+        0xFF, 0x0FF, 0xC0FFEE, 0Xf00,
+        // base 8
+        0, 01234, 07,
+        // corner cases
+        2, 2, 0, 0, 0, INT32_MAX, INT32_MIN,
+        // failing cases
+        DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE,
+        DEFAULT_VALUE, DEFAULT_VALUE,
+    };
+
+    ASSERT_EQ(ARRAY_SIZE(setValues), ARRAY_SIZE(getValues));
+
+    for (size_t i = 0; i < ARRAY_SIZE(setValues); ++i) {
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, setValues[i]));
+
+        int32_t val = property_get_int32(PROPERTY_TEST_KEY, DEFAULT_VALUE);
+        EXPECT_PRED_FORMAT2(AssertEqualHex, getValues[i], val) << "Property was set to '" << setValues[i] << "'";
+    }
+}
+
+} // namespace android
diff --git a/libcutils/tests/memset_mips/Android.mk b/libcutils/tests/memset_mips/Android.mk
deleted file mode 100644
index c22fca9..0000000
--- a/libcutils/tests/memset_mips/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-# 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
deleted file mode 100644
index c8a1a37..0000000
--- a/libcutils/tests/memset_mips/android_memset_dumb.S
+++ /dev/null
@@ -1,36 +0,0 @@
-	.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
deleted file mode 100644
index e918843..0000000
--- a/libcutils/tests/memset_mips/android_memset_test.S
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * 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
deleted file mode 100644
index f8f3a91..0000000
--- a/libcutils/tests/memset_mips/memset_cmips.S
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 4c47001..0000000
--- a/libcutils/tests/memset_mips/memset_omips.S
+++ /dev/null
@@ -1,90 +0,0 @@
-/* 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
deleted file mode 100644
index 9705c65..0000000
--- a/libcutils/tests/memset_mips/test_memset.c
+++ /dev/null
@@ -1,235 +0,0 @@
-#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/threads.c b/libcutils/threads.c
index 42cc928..bf182f0 100644
--- a/libcutils/threads.c
+++ b/libcutils/threads.c
@@ -1,5 +1,4 @@
-/* libs/cutils/threads.c
-**
+/*
 ** Copyright (C) 2007, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License"); 
@@ -14,13 +13,12 @@
 ** See the License for the specific language governing permissions and 
 ** limitations under the License.
 */
+
 #include <cutils/threads.h>
 
 #ifdef HAVE_PTHREADS
 void*  thread_store_get( thread_store_t*  store )
 {
-    const pthread_key_t  k = store->tls;
-
     if (!store->has_tls)
         return NULL;
 
diff --git a/libcutils/trace.c b/libcutils/trace.c
index 9754a44..f57aac2 100644
--- a/libcutils/trace.c
+++ b/libcutils/trace.c
@@ -28,7 +28,7 @@
 #include <cutils/trace.h>
 
 #define LOG_TAG "cutils-trace"
-#include <cutils/log.h>
+#include <log/log.h>
 
 volatile int32_t        atrace_is_ready      = 0;
 int                     atrace_marker_fd     = -1;
@@ -86,7 +86,6 @@
 static bool atrace_is_app_tracing_enabled()
 {
     bool sys_debuggable = false;
-    bool proc_debuggable = false;
     char value[PROPERTY_VALUE_MAX];
     bool result = false;
 
diff --git a/libdiskconfig/Android.mk b/libdiskconfig/Android.mk
index b5d83fa..624e385 100644
--- a/libdiskconfig/Android.mk
+++ b/libdiskconfig/Android.mk
@@ -12,6 +12,7 @@
 LOCAL_MODULE := libdiskconfig
 LOCAL_MODULE_TAGS := optional
 LOCAL_SYSTEM_SHARED_LIBRARIES := libcutils liblog libc
+LOCAL_CFLAGS := -Werror
 include $(BUILD_SHARED_LIBRARY)
 
 ifeq ($(HOST_OS),linux)
diff --git a/libdiskconfig/diskconfig.c b/libdiskconfig/diskconfig.c
index 6fd81b7..1167d4b 100644
--- a/libdiskconfig/diskconfig.c
+++ b/libdiskconfig/diskconfig.c
@@ -30,7 +30,7 @@
 #include <linux/fs.h>
 
 #include <cutils/config_utils.h>
-#include <cutils/log.h>
+#include <log/log.h>
 
 #include <diskconfig/diskconfig.h>
 
@@ -337,7 +337,7 @@
     }
 
 #if 1
-    ALOGV("Device/file %s: size=%llu bytes, num_lba=%u, sect_size=%d",
+    ALOGV("Device/file %s: size=%" PRIu64 " bytes, num_lba=%u, sect_size=%d",
          dinfo->device, disk_size, dinfo->num_lba, dinfo->sect_size);
 #endif
 
diff --git a/libdiskconfig/diskutils.c b/libdiskconfig/diskutils.c
index e325735..5d0ee62 100644
--- a/libdiskconfig/diskutils.c
+++ b/libdiskconfig/diskutils.c
@@ -19,13 +19,14 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <sys/stat.h>
 
-#include <cutils/log.h>
+#include <log/log.h>
 
 #include <diskconfig/diskconfig.h>
 
@@ -35,12 +36,12 @@
     int dst_fd = -1;
     int src_fd = -1;
     uint8_t buffer[2048];
-    int nr_bytes;
-    int tmp;
+    ssize_t nr_bytes;
+    ssize_t tmp;
     int done = 0;
     uint64_t total = 0;
 
-    ALOGI("Writing RAW image '%s' to '%s' (offset=%llu)", src, dst, offset);
+    ALOGI("Writing RAW image '%s' to '%s' (offset=%llu)", src, dst, (unsigned long long)offset);
     if ((src_fd = open(src, O_RDONLY)) < 0) {
         ALOGE("Could not open %s for reading (errno=%d).", src, errno);
         goto fail;
@@ -53,7 +54,7 @@
         }
 
         if (lseek64(dst_fd, offset, SEEK_SET) != offset) {
-            ALOGE("Could not seek to offset %lld in %s.", offset, dst);
+            ALOGE("Could not seek to offset %lld in %s.", (long long)offset, dst);
             goto fail;
         }
     }
@@ -101,7 +102,7 @@
     if (dst_fd >= 0)
         fsync(dst_fd);
 
-    ALOGI("Wrote %llu bytes to %s @ %lld", total, dst, offset);
+    ALOGI("Wrote %" PRIu64 " bytes to %s @ %lld", total, dst, (long long)offset);
 
     close(src_fd);
     if (dst_fd >= 0)
diff --git a/libdiskconfig/write_lst.c b/libdiskconfig/write_lst.c
index 826ef7a..90b1c82 100644
--- a/libdiskconfig/write_lst.c
+++ b/libdiskconfig/write_lst.c
@@ -71,18 +71,18 @@
 {
     for(; lst; lst = lst->next) {
         if (lseek64(fd, lst->offset, SEEK_SET) != (loff_t)lst->offset) {
-            ALOGE("Cannot seek to the specified position (%lld).", lst->offset);
+            ALOGE("Cannot seek to the specified position (%lld).", (long long)lst->offset);
             goto fail;
         }
 
         if (!test) {
             if (write(fd, lst->data, lst->len) != (int)lst->len) {
                 ALOGE("Failed writing %u bytes at position %lld.", lst->len,
-                     lst->offset);
+                     (long long)lst->offset);
                 goto fail;
             }
         } else
-            ALOGI("Would write %d bytes @ offset %lld.", lst->len, lst->offset);
+            ALOGI("Would write %d bytes @ offset %lld.", lst->len, (long long)lst->offset);
     }
 
     return 0;
diff --git a/libion/Android.mk b/libion/Android.mk
index e5d495b..6562cd3 100644
--- a/libion/Android.mk
+++ b/libion/Android.mk
@@ -1,4 +1,4 @@
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := ion.c
@@ -7,6 +7,7 @@
 LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/kernel-headers
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include $(LOCAL_PATH)/kernel-headers
+LOCAL_CFLAGS := -Werror
 include $(BUILD_SHARED_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -15,6 +16,7 @@
 LOCAL_MODULE_TAGS := optional tests
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/kernel-headers
 LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_CFLAGS := -Werror
 include $(BUILD_EXECUTABLE)
 
 include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/liblog/Android.mk b/liblog/Android.mk
index 0d6c970..a7eead9 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -16,7 +16,11 @@
 LOCAL_PATH := $(my-dir)
 include $(CLEAR_VARS)
 
+ifneq ($(TARGET_USES_LOGD),false)
 liblog_sources := logd_write.c
+else
+liblog_sources := logd_write_kern.c
+endif
 
 # some files must not be compiled when building against Mingw
 # they correspond to features not used by our host development tools
@@ -42,19 +46,28 @@
 endif
 
 liblog_host_sources := $(liblog_sources) fake_log_device.c
-liblog_target_sources = $(liblog_sources) log_read.c
+liblog_target_sources := $(liblog_sources) log_time.cpp
+ifneq ($(TARGET_USES_LOGD),false)
+liblog_target_sources += log_read.c
+else
+liblog_target_sources += log_read_kern.c
+endif
 
 # Shared and static library for host
 # ========================================================
 LOCAL_MODULE := liblog
 LOCAL_SRC_FILES := $(liblog_host_sources)
-LOCAL_LDLIBS := -lpthread
-LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1
+LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -Werror
+LOCAL_MULTILIB := both
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := liblog
 LOCAL_WHOLE_STATIC_LIBRARIES := liblog
+ifeq ($(strip $(HOST_OS)),linux)
+LOCAL_LDLIBS := -lrt
+endif
+LOCAL_MULTILIB := both
 include $(BUILD_HOST_SHARED_LIBRARY)
 
 
@@ -63,8 +76,7 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := lib64log
 LOCAL_SRC_FILES := $(liblog_host_sources)
-LOCAL_LDLIBS := -lpthread
-LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -m64
+LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -m64 -Werror
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 # Shared and static library for target
@@ -72,11 +84,13 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := liblog
 LOCAL_SRC_FILES := $(liblog_target_sources)
+LOCAL_CFLAGS := -Werror
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := liblog
 LOCAL_WHOLE_STATIC_LIBRARIES := liblog
+LOCAL_CFLAGS := -Werror
 include $(BUILD_SHARED_LIBRARY)
 
 include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c
index f3d1e2f..bea99aa 100644
--- a/liblog/event_tag_map.c
+++ b/liblog/event_tag_map.c
@@ -13,15 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <log/event_tag_map.h>
-#include <log/log.h>
 
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
-#include <fcntl.h>
 #include <sys/mman.h>
-#include <errno.h>
-#include <assert.h>
+
+#include <log/event_tag_map.h>
+#include <log/log.h>
 
 #define OUT_TAG "EventTagMap"
 
@@ -52,7 +53,6 @@
 static int parseMapLines(EventTagMap* map);
 static int scanTagLine(char** pData, EventTag* tag, int lineNum);
 static int sortTags(EventTagMap* map);
-static void dumpTags(const EventTagMap* map);
 
 
 /*
@@ -185,8 +185,6 @@
  */
 static int processFile(EventTagMap* map)
 {
-    EventTag* tagArray = NULL;
-
     /* get a tag count */
     map->numTags = countMapLines(map);
     if (map->numTags < 0)
@@ -422,17 +420,3 @@
 
     return 0;
 }
-
-/*
- * Dump the tag array for debugging.
- */
-static void dumpTags(const EventTagMap* map)
-{
-    int i;
-
-    for (i = 0; i < map->numTags; i++) {
-        const EventTag* tag = &map->tagArray[i];
-        printf("  %3d: %6d '%s'\n", i, tag->tagIndex, tag->tagStr);
-    }
-}
-
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index da83a85..136792d 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -21,18 +21,22 @@
  */
 #include "fake_log_device.h"
 
-#include <log/logd.h>
-
-#include <stdlib.h>
-#include <string.h>
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <log/logd.h>
 
 #ifdef HAVE_PTHREADS
 #include <pthread.h>
 #endif
 
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
+
 #define kMaxTagLen  16      /* from the long-dead utils/Log.cpp */
 
 #define kTagSetSize 16      /* arbitrary */
@@ -613,7 +617,7 @@
 /*
  * Open a log output device and return a fake fd.
  */
-static int logOpen(const char* pathName, int flags)
+static int logOpen(const char* pathName, int flags __unused)
 {
     LogState *logState;
     int fd = -1;
diff --git a/liblog/log_read.c b/liblog/log_read.c
index 47aa711..ca5a1a7 100644
--- a/liblog/log_read.c
+++ b/liblog/log_read.c
@@ -14,37 +14,180 @@
 ** limitations under the License.
 */
 
-#define _GNU_SOURCE /* asprintf for x86 host */
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <poll.h>
-#include <string.h>
-#include <stdio.h>
+#include <signal.h>
+#include <stddef.h>
+#define NOMINMAX /* for windows to suppress definition of min in stdlib.h */
 #include <stdlib.h>
+#include <string.h>
+#include <sys/cdefs.h>
+#include <unistd.h>
+
 #include <cutils/list.h>
+#include <cutils/sockets.h>
 #include <log/log.h>
 #include <log/logger.h>
 
-#include <sys/ioctl.h>
+/* branchless on many architectures. */
+#define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
 
-#define __LOGGERIO     0xAE
+#define WEAK __attribute__((weak))
+#ifndef __unused
+#define __unused __attribute__((unused))
+#endif
 
-#define LOGGER_GET_LOG_BUF_SIZE    _IO(__LOGGERIO, 1) /* size of log */
-#define LOGGER_GET_LOG_LEN         _IO(__LOGGERIO, 2) /* used log len */
-#define LOGGER_GET_NEXT_ENTRY_LEN  _IO(__LOGGERIO, 3) /* next entry len */
-#define LOGGER_FLUSH_LOG           _IO(__LOGGERIO, 4) /* flush log */
-#define LOGGER_GET_VERSION         _IO(__LOGGERIO, 5) /* abi version */
-#define LOGGER_SET_VERSION         _IO(__LOGGERIO, 6) /* abi version */
+/* Private copy of ../libcutils/socket_local_client.c prevent library loops */
 
-typedef char bool;
-#define false (const bool)0
-#define true (const bool)1
+#ifdef HAVE_WINSOCK
 
-#define LOG_FILE_DIR "/dev/log/"
+int WEAK socket_local_client(const char *name, int namespaceId, int type)
+{
+    errno = ENOSYS;
+    return -ENOSYS;
+}
 
-/* timeout in milliseconds */
-#define LOG_TIMEOUT_FLUSH 5
-#define LOG_TIMEOUT_NEVER -1
+#else /* !HAVE_WINSOCK */
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/select.h>
+#include <sys/types.h>
+
+/* Private copy of ../libcutils/socket_local.h prevent library loops */
+#define FILESYSTEM_SOCKET_PREFIX "/tmp/"
+#define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/"
+/* End of ../libcutils/socket_local.h */
+
+#define LISTEN_BACKLOG 4
+
+/* Documented in header file. */
+int WEAK socket_make_sockaddr_un(const char *name, int namespaceId,
+                                 struct sockaddr_un *p_addr, socklen_t *alen)
+{
+    memset (p_addr, 0, sizeof (*p_addr));
+    size_t namelen;
+
+    switch (namespaceId) {
+    case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
+#ifdef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE
+        namelen  = strlen(name);
+
+        /* Test with length +1 for the *initial* '\0'. */
+        if ((namelen + 1) > sizeof(p_addr->sun_path)) {
+            goto error;
+        }
+
+        /*
+         * Note: The path in this case is *not* supposed to be
+         * '\0'-terminated. ("man 7 unix" for the gory details.)
+         */
+
+        p_addr->sun_path[0] = 0;
+        memcpy(p_addr->sun_path + 1, name, namelen);
+#else /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
+        /* this OS doesn't have the Linux abstract namespace */
+
+        namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
+        /* unix_path_max appears to be missing on linux */
+        if (namelen > sizeof(*p_addr)
+                - offsetof(struct sockaddr_un, sun_path) - 1) {
+            goto error;
+        }
+
+        strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
+        strcat(p_addr->sun_path, name);
+#endif /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
+        break;
+
+    case ANDROID_SOCKET_NAMESPACE_RESERVED:
+        namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
+        /* unix_path_max appears to be missing on linux */
+        if (namelen > sizeof(*p_addr)
+                - offsetof(struct sockaddr_un, sun_path) - 1) {
+            goto error;
+        }
+
+        strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);
+        strcat(p_addr->sun_path, name);
+        break;
+
+    case ANDROID_SOCKET_NAMESPACE_FILESYSTEM:
+        namelen = strlen(name);
+        /* unix_path_max appears to be missing on linux */
+        if (namelen > sizeof(*p_addr)
+                - offsetof(struct sockaddr_un, sun_path) - 1) {
+            goto error;
+        }
+
+        strcpy(p_addr->sun_path, name);
+        break;
+
+    default:
+        /* invalid namespace id */
+        return -1;
+    }
+
+    p_addr->sun_family = AF_LOCAL;
+    *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
+    return 0;
+error:
+    return -1;
+}
+
+/**
+ * connect to peer named "name" on fd
+ * returns same fd or -1 on error.
+ * fd is not closed on error. that's your job.
+ *
+ * Used by AndroidSocketImpl
+ */
+int WEAK socket_local_client_connect(int fd, const char *name, int namespaceId,
+                                     int type __unused)
+{
+    struct sockaddr_un addr;
+    socklen_t alen;
+    int err;
+
+    err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
+
+    if (err < 0) {
+        goto error;
+    }
+
+    if(connect(fd, (struct sockaddr *) &addr, alen) < 0) {
+        goto error;
+    }
+
+    return fd;
+
+error:
+    return -1;
+}
+
+/**
+ * connect to peer named "name"
+ * returns fd or -1 on error
+ */
+int WEAK socket_local_client(const char *name, int namespaceId, int type)
+{
+    int s;
+
+    s = socket(AF_LOCAL, type, 0);
+    if(s < 0) return -1;
+
+    if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) {
+        close(s);
+        return -1;
+    }
+
+    return s;
+}
+
+#endif /* !HAVE_WINSOCK */
+/* End of ../libcutils/socket_local_client.c */
 
 #define logger_for_each(logger, logger_list) \
     for (logger = node_to_item((logger_list)->node.next, struct logger, node); \
@@ -56,47 +199,21 @@
     [LOG_ID_MAIN] = "main",
     [LOG_ID_RADIO] = "radio",
     [LOG_ID_EVENTS] = "events",
-    [LOG_ID_SYSTEM] = "system"
+    [LOG_ID_SYSTEM] = "system",
+    [LOG_ID_CRASH] = "crash",
 };
 
-const char *android_log_id_to_name(log_id_t log_id) {
+const char *android_log_id_to_name(log_id_t log_id)
+{
     if (log_id >= LOG_ID_MAX) {
         log_id = LOG_ID_MAIN;
     }
     return LOG_NAME[log_id];
 }
 
-static int accessmode(int mode)
+log_id_t android_name_to_log_id(const char *logName)
 {
-    if ((mode & O_ACCMODE) == O_WRONLY) {
-        return W_OK;
-    }
-    if ((mode & O_ACCMODE) == O_RDWR) {
-        return R_OK | W_OK;
-    }
-    return R_OK;
-}
-
-/* repeated fragment */
-static int check_allocate_accessible(char **n, const char *b, int mode)
-{
-    *n = NULL;
-
-    if (!b) {
-        return -EINVAL;
-    }
-
-    asprintf(n, LOG_FILE_DIR "%s", b);
-    if (!*n) {
-        return -1;
-    }
-
-    return access(*n, accessmode(mode));
-}
-
-log_id_t android_name_to_log_id(const char *logName) {
     const char *b;
-    char *n;
     int ret;
 
     if (!logName) {
@@ -109,12 +226,6 @@
         ++b;
     }
 
-    ret = check_allocate_accessible(&n, b, O_RDONLY);
-    free(n);
-    if (ret) {
-        return ret;
-    }
-
     for(ret = LOG_ID_MIN; ret < LOG_ID_MAX; ++ret) {
         const char *l = LOG_NAME[ret];
         if (l && !strcmp(b, l)) {
@@ -128,27 +239,15 @@
     struct listnode node;
     int mode;
     unsigned int tail;
+    log_time start;
     pid_t pid;
-    unsigned int queued_lines;
-    int timeout_ms;
-    int error;
-    bool flush;
-    bool valid_entry; /* valiant(?) effort to deal with memory starvation */
-    struct log_msg entry;
-};
-
-struct log_list {
-    struct listnode node;
-    struct log_msg entry; /* Truncated to event->len() + 1 to save space */
+    int sock;
 };
 
 struct logger {
     struct listnode node;
     struct logger_list *top;
-    int fd;
     log_id_t id;
-    short *revents;
-    struct listnode log_list;
 };
 
 /* android_logger_alloc unimplemented, no use case */
@@ -159,91 +258,209 @@
         return;
     }
 
-    while (!list_empty(&logger->log_list)) {
-        struct log_list *entry = node_to_item(
-            list_head(&logger->log_list), struct log_list, node);
-        list_remove(&entry->node);
-        free(entry);
-        if (logger->top->queued_lines) {
-            logger->top->queued_lines--;
-        }
-    }
-
-    if (logger->fd >= 0) {
-        close(logger->fd);
-    }
-
     list_remove(&logger->node);
 
     free(logger);
 }
 
+/* android_logger_alloc unimplemented, no use case */
+
+/* method for getting the associated sublog id */
 log_id_t android_logger_get_id(struct logger *logger)
 {
     return logger->id;
 }
 
 /* worker for sending the command to the logger */
-static int logger_ioctl(struct logger *logger, int cmd, int mode)
+static ssize_t send_log_msg(struct logger *logger,
+                            const char *msg, char *buf, size_t buf_size)
 {
-    char *n;
-    int  f, ret;
-
-    if (!logger || !logger->top) {
-        return -EFAULT;
+    ssize_t ret;
+    size_t len;
+    char *cp;
+    int errno_save = 0;
+    int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
+                                   SOCK_STREAM);
+    if (sock < 0) {
+        return sock;
     }
 
-    if (((mode & O_ACCMODE) == O_RDWR)
-     || (((mode ^ logger->top->mode) & O_ACCMODE) == 0)) {
-        return ioctl(logger->fd, cmd);
+    if (msg) {
+        snprintf(buf, buf_size, msg, logger ? logger->id : (unsigned) -1);
     }
 
-    /* We go here if android_logger_list_open got mode wrong for this ioctl */
-    ret = check_allocate_accessible(&n, android_log_id_to_name(logger->id), mode);
-    if (ret) {
-        free(n);
+    len = strlen(buf) + 1;
+    ret = TEMP_FAILURE_RETRY(write(sock, buf, len));
+    if (ret <= 0) {
+        goto done;
+    }
+
+    len = buf_size;
+    cp = buf;
+    while ((ret = TEMP_FAILURE_RETRY(read(sock, cp, len))) > 0) {
+        struct pollfd p;
+
+        if (((size_t)ret == len) || (buf_size < PAGE_SIZE)) {
+            break;
+        }
+
+        len -= ret;
+        cp += ret;
+
+        memset(&p, 0, sizeof(p));
+        p.fd = sock;
+        p.events = POLLIN;
+
+        /* Give other side 20ms to refill pipe */
+        ret = TEMP_FAILURE_RETRY(poll(&p, 1, 20));
+
+        if (ret <= 0) {
+            break;
+        }
+
+        if (!(p.revents & POLLIN)) {
+            ret = 0;
+            break;
+        }
+    }
+
+    if (ret >= 0) {
+        ret += buf_size - len;
+    }
+
+done:
+    if ((ret == -1) && errno) {
+        errno_save = errno;
+    }
+    close(sock);
+    if (errno_save) {
+        errno = errno_save;
+    }
+    return ret;
+}
+
+static int check_log_success(char *buf, ssize_t ret)
+{
+    if (ret < 0) {
         return ret;
     }
 
-    f = open(n, mode);
-    free(n);
-    if (f < 0) {
-        return f;
+    if (strncmp(buf, "success", 7)) {
+        errno = EINVAL;
+        return -1;
     }
 
-    ret = ioctl(f, cmd);
-    close (f);
-
-    return ret;
+    return 0;
 }
 
 int android_logger_clear(struct logger *logger)
 {
-    return logger_ioctl(logger, LOGGER_FLUSH_LOG, O_WRONLY);
+    char buf[512];
+
+    return check_log_success(buf,
+        send_log_msg(logger, "clear %d", buf, sizeof(buf)));
 }
 
 /* returns the total size of the log's ring buffer */
-int android_logger_get_log_size(struct logger *logger)
+long android_logger_get_log_size(struct logger *logger)
 {
-    return logger_ioctl(logger, LOGGER_GET_LOG_BUF_SIZE, O_RDWR);
+    char buf[512];
+
+    ssize_t ret = send_log_msg(logger, "getLogSize %d", buf, sizeof(buf));
+    if (ret < 0) {
+        return ret;
+    }
+
+    if ((buf[0] < '0') || ('9' < buf[0])) {
+        return -1;
+    }
+
+    return atol(buf);
+}
+
+int android_logger_set_log_size(struct logger *logger, unsigned long size)
+{
+    char buf[512];
+
+    snprintf(buf, sizeof(buf), "setLogSize %d %lu",
+        logger ? logger->id : (unsigned) -1, size);
+
+    return check_log_success(buf, send_log_msg(NULL, NULL, buf, sizeof(buf)));
 }
 
 /*
  * returns the readable size of the log's ring buffer (that is, amount of the
  * log consumed)
  */
-int android_logger_get_log_readable_size(struct logger *logger)
+long android_logger_get_log_readable_size(struct logger *logger)
 {
-    return logger_ioctl(logger, LOGGER_GET_LOG_LEN, O_RDONLY);
+    char buf[512];
+
+    ssize_t ret = send_log_msg(logger, "getLogSizeUsed %d", buf, sizeof(buf));
+    if (ret < 0) {
+        return ret;
+    }
+
+    if ((buf[0] < '0') || ('9' < buf[0])) {
+        return -1;
+    }
+
+    return atol(buf);
 }
 
 /*
  * returns the logger version
  */
-int android_logger_get_log_version(struct logger *logger)
+int android_logger_get_log_version(struct logger *logger __unused)
 {
-    int ret = logger_ioctl(logger, LOGGER_GET_VERSION, O_RDWR);
-    return (ret < 0) ? 1 : ret;
+    return 3;
+}
+
+/*
+ * returns statistics
+ */
+ssize_t android_logger_get_statistics(struct logger_list *logger_list,
+                                      char *buf, size_t len)
+{
+    struct logger *logger;
+    char *cp = buf;
+    size_t remaining = len;
+    size_t n;
+
+    n = snprintf(cp, remaining, "getStatistics");
+    n = min(n, remaining);
+    remaining -= n;
+    cp += n;
+
+    logger_for_each(logger, logger_list) {
+        n = snprintf(cp, remaining, " %d", logger->id);
+        n = min(n, remaining);
+        remaining -= n;
+        cp += n;
+    }
+    return send_log_msg(NULL, NULL, buf, len);
+}
+
+ssize_t android_logger_get_prune_list(struct logger_list *logger_list __unused,
+                                      char *buf, size_t len)
+{
+    return send_log_msg(NULL, "getPruneList", buf, len);
+}
+
+int android_logger_set_prune_list(struct logger_list *logger_list __unused,
+                                  char *buf, size_t len)
+{
+    const char cmd[] = "setPruneList ";
+    const size_t cmdlen = sizeof(cmd) - 1;
+
+    if (strlen(buf) > (len - cmdlen)) {
+        return -ENOMEM; /* KISS */
+    }
+    memmove(buf + cmdlen, buf, len - cmdlen);
+    buf[len - 1] = '\0';
+    memcpy(buf, cmd, cmdlen);
+
+    return check_log_success(buf, send_log_msg(NULL, NULL, buf, len));
 }
 
 struct logger_list *android_logger_list_alloc(int mode,
@@ -256,10 +473,36 @@
     if (!logger_list) {
         return NULL;
     }
+
     list_init(&logger_list->node);
     logger_list->mode = mode;
+    logger_list->start.tv_sec = 0;
+    logger_list->start.tv_nsec = 0;
     logger_list->tail = tail;
     logger_list->pid = pid;
+    logger_list->sock = -1;
+
+    return logger_list;
+}
+
+struct logger_list *android_logger_list_alloc_time(int mode,
+                                                   log_time start,
+                                                   pid_t pid)
+{
+    struct logger_list *logger_list;
+
+    logger_list = calloc(1, sizeof(*logger_list));
+    if (!logger_list) {
+        return NULL;
+    }
+
+    list_init(&logger_list->node);
+    logger_list->mode = mode;
+    logger_list->start = start;
+    logger_list->tail = 0;
+    logger_list->pid = pid;
+    logger_list->sock = -1;
+
     return logger_list;
 }
 
@@ -270,9 +513,7 @@
 struct logger *android_logger_open(struct logger_list *logger_list,
                                    log_id_t id)
 {
-    struct listnode *node;
     struct logger *logger;
-    char *n;
 
     if (!logger_list || (id >= LOG_ID_MAX)) {
         goto err;
@@ -289,28 +530,11 @@
         goto err;
     }
 
-    if (check_allocate_accessible(&n, android_log_id_to_name(id),
-                                  logger_list->mode)) {
-        goto err_name;
-    }
-
-    logger->fd = open(n, logger_list->mode);
-    if (logger->fd < 0) {
-        goto err_name;
-    }
-
-    free(n);
     logger->id = id;
-    list_init(&logger->log_list);
     list_add_tail(&logger_list->node, &logger->node);
     logger->top = logger_list;
-    logger_list->timeout_ms = LOG_TIMEOUT_FLUSH;
     goto ok;
 
-err_name:
-    free(n);
-err_logger:
-    free(logger);
 err:
     logger = NULL;
 ok:
@@ -336,315 +560,146 @@
     return logger_list;
 }
 
-/* prevent memory starvation when backfilling */
-static unsigned int queue_threshold(struct logger_list *logger_list)
+static void caught_signal(int signum __unused)
 {
-    return (logger_list->tail < 64) ? 64 : logger_list->tail;
-}
-
-static bool low_queue(struct listnode *node)
-{
-    /* low is considered less than 2 */
-    return list_head(node) == list_tail(node);
-}
-
-/* Flush queues in sequential order, one at a time */
-static int android_logger_list_flush(struct logger_list *logger_list,
-                                     struct log_msg *log_msg)
-{
-    int ret = 0;
-    struct log_list *firstentry = NULL;
-
-    while ((ret == 0)
-     && (logger_list->flush
-      || (logger_list->queued_lines > logger_list->tail))) {
-        struct logger *logger;
-
-        /* Merge sort */
-        bool at_least_one_is_low = false;
-        struct logger *firstlogger = NULL;
-        firstentry = NULL;
-
-        logger_for_each(logger, logger_list) {
-            struct listnode *node;
-            struct log_list *oldest = NULL;
-
-            /* kernel logger channels not necessarily time-sort order */
-            list_for_each(node, &logger->log_list) {
-                struct log_list *entry = node_to_item(node,
-                                                      struct log_list, node);
-                if (!oldest
-                 || (entry->entry.entry.sec < oldest->entry.entry.sec)
-                 || ((entry->entry.entry.sec == oldest->entry.entry.sec)
-                  && (entry->entry.entry.nsec < oldest->entry.entry.nsec))) {
-                     oldest = entry;
-                }
-            }
-
-            if (!oldest) {
-                at_least_one_is_low = true;
-                continue;
-            } else if (low_queue(&logger->log_list)) {
-                at_least_one_is_low = true;
-            }
-
-            if (!firstentry
-             || (oldest->entry.entry.sec < firstentry->entry.entry.sec)
-             || ((oldest->entry.entry.sec == firstentry->entry.entry.sec)
-              && (oldest->entry.entry.nsec < firstentry->entry.entry.nsec))) {
-                firstentry = oldest;
-                firstlogger = logger;
-            }
-        }
-
-        if (!firstentry) {
-            break;
-        }
-
-        /* when trimming list, tries to keep one entry behind in each bucket */
-        if (!logger_list->flush
-         && at_least_one_is_low
-         && (logger_list->queued_lines < queue_threshold(logger_list))) {
-            break;
-        }
-
-        /* within tail?, send! */
-        if ((logger_list->tail == 0)
-         || (logger_list->queued_lines <= logger_list->tail)) {
-            ret = firstentry->entry.entry.hdr_size;
-            if (!ret) {
-                ret = sizeof(firstentry->entry.entry_v1);
-            }
-            ret += firstentry->entry.entry.len;
-
-            memcpy(log_msg->buf, firstentry->entry.buf, ret + 1);
-            log_msg->extra.id = firstlogger->id;
-        }
-
-        /* next entry */
-        list_remove(&firstentry->node);
-        free(firstentry);
-        if (logger_list->queued_lines) {
-            logger_list->queued_lines--;
-        }
-    }
-
-    /* Flushed the list, no longer in tail mode for continuing content */
-    if (logger_list->flush && !firstentry) {
-        logger_list->tail = 0;
-    }
-    return ret;
 }
 
 /* Read from the selected logs */
 int android_logger_list_read(struct logger_list *logger_list,
                              struct log_msg *log_msg)
 {
+    int ret, e;
     struct logger *logger;
-    nfds_t nfds;
-    struct pollfd *p, *pollfds = NULL;
-    int error = 0, ret = 0;
-
-    memset(log_msg, 0, sizeof(struct log_msg));
+    struct sigaction ignore;
+    struct sigaction old_sigaction;
+    unsigned int old_alarm = 0;
 
     if (!logger_list) {
-        return -ENODEV;
+        return -EINVAL;
     }
 
-    if (!(accessmode(logger_list->mode) & R_OK)) {
-        logger_list->error = EPERM;
-        goto done;
+    if (logger_list->mode & O_NONBLOCK) {
+        memset(&ignore, 0, sizeof(ignore));
+        ignore.sa_handler = caught_signal;
+        sigemptyset(&ignore.sa_mask);
     }
 
-    nfds = 0;
-    logger_for_each(logger, logger_list) {
-        ++nfds;
-    }
-    if (nfds <= 0) {
-        error = ENODEV;
-        goto done;
-    }
+    if (logger_list->sock < 0) {
+        char buffer[256], *cp, c;
 
-    /* Do we have anything to offer from the buffer or state? */
-    if (logger_list->valid_entry) { /* implies we are also in a flush state */
-        goto flush;
-    }
-
-    ret = android_logger_list_flush(logger_list, log_msg);
-    if (ret) {
-        goto done;
-    }
-
-    if (logger_list->error) { /* implies we are also in a flush state */
-        goto done;
-    }
-
-    /* Lets start grinding on metal */
-    pollfds = calloc(nfds, sizeof(struct pollfd));
-    if (!pollfds) {
-        error = ENOMEM;
-        goto flush;
-    }
-
-    p = pollfds;
-    logger_for_each(logger, logger_list) {
-        p->fd = logger->fd;
-        p->events = POLLIN;
-        logger->revents = &p->revents;
-        ++p;
-    }
-
-    while (!ret && !error) {
-        int result;
-
-        /* If we oversleep it's ok, i.e. ignore EINTR. */
-        result = TEMP_FAILURE_RETRY(
-            poll(pollfds, nfds, logger_list->timeout_ms));
-
-        if (result <= 0) {
-            if (result) {
-                error = errno;
-            } else if (logger_list->mode & O_NDELAY) {
-                error = EAGAIN;
-            } else {
-                logger_list->timeout_ms = LOG_TIMEOUT_NEVER;
+        int sock = socket_local_client("logdr",
+                                       ANDROID_SOCKET_NAMESPACE_RESERVED,
+                                       SOCK_SEQPACKET);
+        if (sock < 0) {
+            if ((sock == -1) && errno) {
+                return -errno;
             }
-
-            logger_list->flush = true;
-            goto try_flush;
+            return sock;
         }
 
-        logger_list->timeout_ms = LOG_TIMEOUT_FLUSH;
+        strcpy(buffer,
+               (logger_list->mode & O_NONBLOCK) ? "dumpAndClose" : "stream");
+        cp = buffer + strlen(buffer);
 
-        /* Anti starvation */
-        if (!logger_list->flush
-         && (logger_list->queued_lines > (queue_threshold(logger_list) / 2))) {
-            /* Any queues with input pending that is low? */
-            bool starving = false;
-            logger_for_each(logger, logger_list) {
-                if ((*(logger->revents) & POLLIN)
-                 && low_queue(&logger->log_list)) {
-                    starving = true;
-                    break;
-                }
-            }
-
-            /* pushback on any queues that are not low */
-            if (starving) {
-                logger_for_each(logger, logger_list) {
-                    if ((*(logger->revents) & POLLIN)
-                     && !low_queue(&logger->log_list)) {
-                        *(logger->revents) &= ~POLLIN;
-                    }
-                }
-            }
-        }
-
+        strcpy(cp, " lids");
+        cp += 5;
+        c = '=';
+        int remaining = sizeof(buffer) - (cp - buffer);
         logger_for_each(logger, logger_list) {
-            unsigned int hdr_size;
-            struct log_list *entry;
+            ret = snprintf(cp, remaining, "%c%u", c, logger->id);
+            ret = min(ret, remaining);
+            remaining -= ret;
+            cp += ret;
+            c = ',';
+        }
 
-            if (!(*(logger->revents) & POLLIN)) {
-                continue;
+        if (logger_list->tail) {
+            ret = snprintf(cp, remaining, " tail=%u", logger_list->tail);
+            ret = min(ret, remaining);
+            remaining -= ret;
+            cp += ret;
+        }
+
+        if (logger_list->start.tv_sec || logger_list->start.tv_nsec) {
+            ret = snprintf(cp, remaining, " start=%" PRIu32 ".%09" PRIu32,
+                           logger_list->start.tv_sec,
+                           logger_list->start.tv_nsec);
+            ret = min(ret, remaining);
+            remaining -= ret;
+            cp += ret;
+        }
+
+        if (logger_list->pid) {
+            ret = snprintf(cp, remaining, " pid=%u", logger_list->pid);
+            ret = min(ret, remaining);
+            remaining -= ret;
+            cp += ret;
+        }
+
+        if (logger_list->mode & O_NONBLOCK) {
+            /* Deal with an unresponsive logd */
+            sigaction(SIGALRM, &ignore, &old_sigaction);
+            old_alarm = alarm(30);
+        }
+        ret = write(sock, buffer, cp - buffer);
+        e = errno;
+        if (logger_list->mode & O_NONBLOCK) {
+            if (e == EINTR) {
+                e = ETIMEDOUT;
             }
-
-            memset(logger_list->entry.buf, 0, sizeof(struct log_msg));
-            /* NOTE: driver guarantees we read exactly one full entry */
-            result = read(logger->fd, logger_list->entry.buf,
-                          LOGGER_ENTRY_MAX_LEN);
-            if (result <= 0) {
-                if (!result) {
-                    error = EIO;
-                } else if (errno != EINTR) {
-                    error = errno;
-                }
-                continue;
-            }
-
-            if (logger_list->pid
-             && (logger_list->pid != logger_list->entry.entry.pid)) {
-                continue;
-            }
-
-            hdr_size = logger_list->entry.entry.hdr_size;
-            if (!hdr_size) {
-                hdr_size = sizeof(logger_list->entry.entry_v1);
-            }
-
-            if ((hdr_size > sizeof(struct log_msg))
-             || (logger_list->entry.entry.len
-               > sizeof(logger_list->entry.buf) - hdr_size)
-             || (logger_list->entry.entry.len != result - hdr_size)) {
-                error = EINVAL;
-                continue;
-            }
-
-            logger_list->entry.extra.id = logger->id;
-
-            /* speedup: If not tail, and only one list, send directly */
-            if (!logger_list->tail
-             && (list_head(&logger_list->node)
-              == list_tail(&logger_list->node))) {
-                ret = result;
-                memcpy(log_msg->buf, logger_list->entry.buf, result + 1);
-                log_msg->extra.id = logger->id;
-                break;
-            }
-
-            entry = malloc(sizeof(*entry) - sizeof(entry->entry) + result + 1);
-
-            if (!entry) {
-                logger_list->valid_entry = true;
-                error = ENOMEM;
-                break;
-            }
-
-            logger_list->queued_lines++;
-
-            memcpy(entry->entry.buf, logger_list->entry.buf, result);
-            entry->entry.buf[result] = '\0';
-            list_add_tail(&logger->log_list, &entry->node);
+            alarm(old_alarm);
+            sigaction(SIGALRM, &old_sigaction, NULL);
         }
 
         if (ret <= 0) {
-try_flush:
-            ret = android_logger_list_flush(logger_list, log_msg);
-        }
-    }
-
-    free(pollfds);
-
-flush:
-    if (error) {
-        logger_list->flush = true;
-    }
-
-    if (ret <= 0) {
-        ret = android_logger_list_flush(logger_list, log_msg);
-
-        if (!ret && logger_list->valid_entry) {
-            ret = logger_list->entry.entry.hdr_size;
-            if (!ret) {
-                ret = sizeof(logger_list->entry.entry_v1);
+            close(sock);
+            if ((ret == -1) && e) {
+                return -e;
             }
-            ret += logger_list->entry.entry.len;
-
-            memcpy(log_msg->buf, logger_list->entry.buf,
-                   sizeof(struct log_msg));
-            logger_list->valid_entry = false;
+            if (ret == 0) {
+                return -EIO;
+            }
+            return ret;
         }
+
+        logger_list->sock = sock;
     }
 
-done:
-    if (logger_list->error) {
-        error = logger_list->error;
-    }
-    if (error) {
-        logger_list->error = error;
-        if (!ret) {
-            ret = -error;
+    ret = 0;
+    while(1) {
+        memset(log_msg, 0, sizeof(*log_msg));
+
+        if (logger_list->mode & O_NONBLOCK) {
+            /* particularily useful if tombstone is reporting for logd */
+            sigaction(SIGALRM, &ignore, &old_sigaction);
+            old_alarm = alarm(30);
+        }
+        /* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
+        ret = recv(logger_list->sock, log_msg, LOGGER_ENTRY_MAX_LEN, 0);
+        e = errno;
+        if (logger_list->mode & O_NONBLOCK) {
+            if ((ret == 0) || (e == EINTR)) {
+                e = EAGAIN;
+                ret = -1;
+            }
+            alarm(old_alarm);
+            sigaction(SIGALRM, &old_sigaction, NULL);
+        }
+
+        if (ret <= 0) {
+            if ((ret == -1) && e) {
+                return -e;
+            }
+            return ret;
+        }
+
+        logger_for_each(logger, logger_list) {
+            if (log_msg->entry.lid == logger->id) {
+                return ret;
+            }
         }
     }
+    /* NOTREACH */
     return ret;
 }
 
@@ -661,5 +716,9 @@
         android_logger_free(logger);
     }
 
+    if (logger_list->sock >= 0) {
+        close (logger_list->sock);
+    }
+
     free(logger_list);
 }
diff --git a/liblog/log_read_kern.c b/liblog/log_read_kern.c
new file mode 100644
index 0000000..41b8a51
--- /dev/null
+++ b/liblog/log_read_kern.c
@@ -0,0 +1,741 @@
+/*
+** Copyright 2013-2014, 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 _GNU_SOURCE /* asprintf for x86 host */
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/cdefs.h>
+#include <sys/ioctl.h>
+
+#include <cutils/list.h>
+#include <log/log.h>
+#include <log/logger.h>
+
+#define __LOGGERIO     0xAE
+
+#define LOGGER_GET_LOG_BUF_SIZE    _IO(__LOGGERIO, 1) /* size of log */
+#define LOGGER_GET_LOG_LEN         _IO(__LOGGERIO, 2) /* used log len */
+#define LOGGER_GET_NEXT_ENTRY_LEN  _IO(__LOGGERIO, 3) /* next entry len */
+#define LOGGER_FLUSH_LOG           _IO(__LOGGERIO, 4) /* flush log */
+#define LOGGER_GET_VERSION         _IO(__LOGGERIO, 5) /* abi version */
+#define LOGGER_SET_VERSION         _IO(__LOGGERIO, 6) /* abi version */
+
+typedef char bool;
+#define false (const bool)0
+#define true (const bool)1
+
+#define LOG_FILE_DIR "/dev/log/"
+
+/* timeout in milliseconds */
+#define LOG_TIMEOUT_FLUSH 5
+#define LOG_TIMEOUT_NEVER -1
+
+#define logger_for_each(logger, logger_list) \
+    for (logger = node_to_item((logger_list)->node.next, struct logger, node); \
+         logger != node_to_item(&(logger_list)->node, struct logger, node); \
+         logger = node_to_item((logger)->node.next, struct logger, node))
+
+#ifndef __unused
+#define __unused __attribute__((unused))
+#endif
+
+/* In the future, we would like to make this list extensible */
+static const char *LOG_NAME[LOG_ID_MAX] = {
+    [LOG_ID_MAIN] = "main",
+    [LOG_ID_RADIO] = "radio",
+    [LOG_ID_EVENTS] = "events",
+    [LOG_ID_SYSTEM] = "system",
+    [LOG_ID_CRASH] = "crash"
+};
+
+const char *android_log_id_to_name(log_id_t log_id)
+{
+    if (log_id >= LOG_ID_MAX) {
+        log_id = LOG_ID_MAIN;
+    }
+    return LOG_NAME[log_id];
+}
+
+static int accessmode(int mode)
+{
+    if ((mode & O_ACCMODE) == O_WRONLY) {
+        return W_OK;
+    }
+    if ((mode & O_ACCMODE) == O_RDWR) {
+        return R_OK | W_OK;
+    }
+    return R_OK;
+}
+
+/* repeated fragment */
+static int check_allocate_accessible(char **n, const char *b, int mode)
+{
+    *n = NULL;
+
+    if (!b) {
+        return -EINVAL;
+    }
+
+    asprintf(n, LOG_FILE_DIR "%s", b);
+    if (!*n) {
+        return -1;
+    }
+
+    return access(*n, accessmode(mode));
+}
+
+log_id_t android_name_to_log_id(const char *logName)
+{
+    const char *b;
+    char *n;
+    int ret;
+
+    if (!logName) {
+        return -1; /* NB: log_id_t is unsigned */
+    }
+    b = strrchr(logName, '/');
+    if (!b) {
+        b = logName;
+    } else {
+        ++b;
+    }
+
+    ret = check_allocate_accessible(&n, b, O_RDONLY);
+    free(n);
+    if (ret) {
+        return ret;
+    }
+
+    for(ret = LOG_ID_MIN; ret < LOG_ID_MAX; ++ret) {
+        const char *l = LOG_NAME[ret];
+        if (l && !strcmp(b, l)) {
+            return ret;
+        }
+    }
+    return -1;   /* should never happen */
+}
+
+struct logger_list {
+    struct listnode node;
+    int mode;
+    unsigned int tail;
+    pid_t pid;
+    unsigned int queued_lines;
+    int timeout_ms;
+    int error;
+    bool flush;
+    bool valid_entry; /* valiant(?) effort to deal with memory starvation */
+    struct log_msg entry;
+};
+
+struct log_list {
+    struct listnode node;
+    struct log_msg entry; /* Truncated to event->len() + 1 to save space */
+};
+
+struct logger {
+    struct listnode node;
+    struct logger_list *top;
+    int fd;
+    log_id_t id;
+    short *revents;
+    struct listnode log_list;
+};
+
+/* android_logger_alloc unimplemented, no use case */
+/* android_logger_free not exported */
+static void android_logger_free(struct logger *logger)
+{
+    if (!logger) {
+        return;
+    }
+
+    while (!list_empty(&logger->log_list)) {
+        struct log_list *entry = node_to_item(
+            list_head(&logger->log_list), struct log_list, node);
+        list_remove(&entry->node);
+        free(entry);
+        if (logger->top->queued_lines) {
+            logger->top->queued_lines--;
+        }
+    }
+
+    if (logger->fd >= 0) {
+        close(logger->fd);
+    }
+
+    list_remove(&logger->node);
+
+    free(logger);
+}
+
+log_id_t android_logger_get_id(struct logger *logger)
+{
+    return logger->id;
+}
+
+/* worker for sending the command to the logger */
+static int logger_ioctl(struct logger *logger, int cmd, int mode)
+{
+    char *n;
+    int  f, ret;
+
+    if (!logger || !logger->top) {
+        return -EFAULT;
+    }
+
+    if (((mode & O_ACCMODE) == O_RDWR)
+            || (((mode ^ logger->top->mode) & O_ACCMODE) == 0)) {
+        return ioctl(logger->fd, cmd);
+    }
+
+    /* We go here if android_logger_list_open got mode wrong for this ioctl */
+    ret = check_allocate_accessible(&n, android_log_id_to_name(logger->id), mode);
+    if (ret) {
+        free(n);
+        return ret;
+    }
+
+    f = open(n, mode);
+    free(n);
+    if (f < 0) {
+        return f;
+    }
+
+    ret = ioctl(f, cmd);
+    close (f);
+
+    return ret;
+}
+
+int android_logger_clear(struct logger *logger)
+{
+    return logger_ioctl(logger, LOGGER_FLUSH_LOG, O_WRONLY);
+}
+
+/* returns the total size of the log's ring buffer */
+long android_logger_get_log_size(struct logger *logger)
+{
+    return logger_ioctl(logger, LOGGER_GET_LOG_BUF_SIZE, O_RDWR);
+}
+
+int android_logger_set_log_size(struct logger *logger __unused,
+                                unsigned long size __unused)
+{
+    return -ENOTSUP;
+}
+
+/*
+ * returns the readable size of the log's ring buffer (that is, amount of the
+ * log consumed)
+ */
+long android_logger_get_log_readable_size(struct logger *logger)
+{
+    return logger_ioctl(logger, LOGGER_GET_LOG_LEN, O_RDONLY);
+}
+
+/*
+ * returns the logger version
+ */
+int android_logger_get_log_version(struct logger *logger)
+{
+    int ret = logger_ioctl(logger, LOGGER_GET_VERSION, O_RDWR);
+    return (ret < 0) ? 1 : ret;
+}
+
+/*
+ * returns statistics
+ */
+static const char unsupported[] = "18\nNot Supported\n\f";
+
+ssize_t android_logger_get_statistics(struct logger_list *logger_list __unused,
+                                      char *buf, size_t len)
+{
+    strncpy(buf, unsupported, len);
+    return -ENOTSUP;
+}
+
+ssize_t android_logger_get_prune_list(struct logger_list *logger_list __unused,
+                                      char *buf, size_t len)
+{
+    strncpy(buf, unsupported, len);
+    return -ENOTSUP;
+}
+
+int android_logger_set_prune_list(struct logger_list *logger_list __unused,
+                                  char *buf, size_t len)
+{
+    static const char unsupported_error[] = "Unsupported";
+    strncpy(buf, unsupported, len);
+    return -ENOTSUP;
+}
+
+struct logger_list *android_logger_list_alloc(int mode,
+                                              unsigned int tail,
+                                              pid_t pid)
+{
+    struct logger_list *logger_list;
+
+    logger_list = calloc(1, sizeof(*logger_list));
+    if (!logger_list) {
+        return NULL;
+    }
+    list_init(&logger_list->node);
+    logger_list->mode = mode;
+    logger_list->tail = tail;
+    logger_list->pid = pid;
+    return logger_list;
+}
+
+struct logger_list *android_logger_list_alloc_time(int mode,
+                                                   log_time start __unused,
+                                                   pid_t pid)
+{
+    return android_logger_list_alloc(mode, 0, pid);
+}
+
+/* android_logger_list_register unimplemented, no use case */
+/* android_logger_list_unregister unimplemented, no use case */
+
+/* Open the named log and add it to the logger list */
+struct logger *android_logger_open(struct logger_list *logger_list,
+                                   log_id_t id)
+{
+    struct listnode *node;
+    struct logger *logger;
+    char *n;
+
+    if (!logger_list || (id >= LOG_ID_MAX)) {
+        goto err;
+    }
+
+    logger_for_each(logger, logger_list) {
+        if (logger->id == id) {
+            goto ok;
+        }
+    }
+
+    logger = calloc(1, sizeof(*logger));
+    if (!logger) {
+        goto err;
+    }
+
+    if (check_allocate_accessible(&n, android_log_id_to_name(id),
+                                  logger_list->mode)) {
+        goto err_name;
+    }
+
+    logger->fd = open(n, logger_list->mode);
+    if (logger->fd < 0) {
+        goto err_name;
+    }
+
+    free(n);
+    logger->id = id;
+    list_init(&logger->log_list);
+    list_add_tail(&logger_list->node, &logger->node);
+    logger->top = logger_list;
+    logger_list->timeout_ms = LOG_TIMEOUT_FLUSH;
+    goto ok;
+
+err_name:
+    free(n);
+err_logger:
+    free(logger);
+err:
+    logger = NULL;
+ok:
+    return logger;
+}
+
+/* Open the single named log and make it part of a new logger list */
+struct logger_list *android_logger_list_open(log_id_t id,
+                                             int mode,
+                                             unsigned int tail,
+                                             pid_t pid)
+{
+    struct logger_list *logger_list = android_logger_list_alloc(mode, tail, pid);
+    if (!logger_list) {
+        return NULL;
+    }
+
+    if (!android_logger_open(logger_list, id)) {
+        android_logger_list_free(logger_list);
+        return NULL;
+    }
+
+    return logger_list;
+}
+
+/* prevent memory starvation when backfilling */
+static unsigned int queue_threshold(struct logger_list *logger_list)
+{
+    return (logger_list->tail < 64) ? 64 : logger_list->tail;
+}
+
+static bool low_queue(struct listnode *node)
+{
+    /* low is considered less than 2 */
+    return list_head(node) == list_tail(node);
+}
+
+/* Flush queues in sequential order, one at a time */
+static int android_logger_list_flush(struct logger_list *logger_list,
+                                     struct log_msg *log_msg)
+{
+    int ret = 0;
+    struct log_list *firstentry = NULL;
+
+    while ((ret == 0)
+            && (logger_list->flush
+                || (logger_list->queued_lines > logger_list->tail))) {
+        struct logger *logger;
+
+        /* Merge sort */
+        bool at_least_one_is_low = false;
+        struct logger *firstlogger = NULL;
+        firstentry = NULL;
+
+        logger_for_each(logger, logger_list) {
+            struct listnode *node;
+            struct log_list *oldest = NULL;
+
+            /* kernel logger channels not necessarily time-sort order */
+            list_for_each(node, &logger->log_list) {
+                struct log_list *entry = node_to_item(node,
+                                                      struct log_list, node);
+                if (!oldest
+                        || (entry->entry.entry.sec < oldest->entry.entry.sec)
+                        || ((entry->entry.entry.sec == oldest->entry.entry.sec)
+                            && (entry->entry.entry.nsec < oldest->entry.entry.nsec))) {
+                    oldest = entry;
+                }
+            }
+
+            if (!oldest) {
+                at_least_one_is_low = true;
+                continue;
+            } else if (low_queue(&logger->log_list)) {
+                at_least_one_is_low = true;
+            }
+
+            if (!firstentry
+                    || (oldest->entry.entry.sec < firstentry->entry.entry.sec)
+                    || ((oldest->entry.entry.sec == firstentry->entry.entry.sec)
+                        && (oldest->entry.entry.nsec < firstentry->entry.entry.nsec))) {
+                firstentry = oldest;
+                firstlogger = logger;
+            }
+        }
+
+        if (!firstentry) {
+            break;
+        }
+
+        /* when trimming list, tries to keep one entry behind in each bucket */
+        if (!logger_list->flush
+                && at_least_one_is_low
+                && (logger_list->queued_lines < queue_threshold(logger_list))) {
+            break;
+        }
+
+        /* within tail?, send! */
+        if ((logger_list->tail == 0)
+                || (logger_list->queued_lines <= logger_list->tail)) {
+            int diff;
+            ret = firstentry->entry.entry.hdr_size;
+            if (!ret) {
+                ret = sizeof(firstentry->entry.entry_v1);
+            }
+
+            /* Promote entry to v3 format */
+            memcpy(log_msg->buf, firstentry->entry.buf, ret);
+            diff = sizeof(firstentry->entry.entry_v3) - ret;
+            if (diff < 0) {
+                diff = 0;
+            } else if (diff > 0) {
+                memset(log_msg->buf + ret, 0, diff);
+            }
+            memcpy(log_msg->buf + ret + diff, firstentry->entry.buf + ret,
+                   firstentry->entry.entry.len + 1);
+            ret += diff;
+            log_msg->entry.hdr_size = ret;
+            log_msg->entry.lid = firstlogger->id;
+
+            ret += firstentry->entry.entry.len;
+        }
+
+        /* next entry */
+        list_remove(&firstentry->node);
+        free(firstentry);
+        if (logger_list->queued_lines) {
+            logger_list->queued_lines--;
+        }
+    }
+
+    /* Flushed the list, no longer in tail mode for continuing content */
+    if (logger_list->flush && !firstentry) {
+        logger_list->tail = 0;
+    }
+    return ret;
+}
+
+/* Read from the selected logs */
+int android_logger_list_read(struct logger_list *logger_list,
+                             struct log_msg *log_msg)
+{
+    struct logger *logger;
+    nfds_t nfds;
+    struct pollfd *p, *pollfds = NULL;
+    int error = 0, ret = 0;
+
+    memset(log_msg, 0, sizeof(struct log_msg));
+
+    if (!logger_list) {
+        return -ENODEV;
+    }
+
+    if (!(accessmode(logger_list->mode) & R_OK)) {
+        logger_list->error = EPERM;
+        goto done;
+    }
+
+    nfds = 0;
+    logger_for_each(logger, logger_list) {
+        ++nfds;
+    }
+    if (nfds <= 0) {
+        error = ENODEV;
+        goto done;
+    }
+
+    /* Do we have anything to offer from the buffer or state? */
+    if (logger_list->valid_entry) { /* implies we are also in a flush state */
+        goto flush;
+    }
+
+    ret = android_logger_list_flush(logger_list, log_msg);
+    if (ret) {
+        goto done;
+    }
+
+    if (logger_list->error) { /* implies we are also in a flush state */
+        goto done;
+    }
+
+    /* Lets start grinding on metal */
+    pollfds = calloc(nfds, sizeof(struct pollfd));
+    if (!pollfds) {
+        error = ENOMEM;
+        goto flush;
+    }
+
+    p = pollfds;
+    logger_for_each(logger, logger_list) {
+        p->fd = logger->fd;
+        p->events = POLLIN;
+        logger->revents = &p->revents;
+        ++p;
+    }
+
+    while (!ret && !error) {
+        int result;
+
+        /* If we oversleep it's ok, i.e. ignore EINTR. */
+        result = TEMP_FAILURE_RETRY(
+                    poll(pollfds, nfds, logger_list->timeout_ms));
+
+        if (result <= 0) {
+            if (result) {
+                error = errno;
+            } else if (logger_list->mode & O_NDELAY) {
+                error = EAGAIN;
+            } else {
+                logger_list->timeout_ms = LOG_TIMEOUT_NEVER;
+            }
+
+            logger_list->flush = true;
+            goto try_flush;
+        }
+
+        logger_list->timeout_ms = LOG_TIMEOUT_FLUSH;
+
+        /* Anti starvation */
+        if (!logger_list->flush
+                && (logger_list->queued_lines > (queue_threshold(logger_list) / 2))) {
+            /* Any queues with input pending that is low? */
+            bool starving = false;
+            logger_for_each(logger, logger_list) {
+                if ((*(logger->revents) & POLLIN)
+                        && low_queue(&logger->log_list)) {
+                    starving = true;
+                    break;
+                }
+            }
+
+            /* pushback on any queues that are not low */
+            if (starving) {
+                logger_for_each(logger, logger_list) {
+                    if ((*(logger->revents) & POLLIN)
+                            && !low_queue(&logger->log_list)) {
+                        *(logger->revents) &= ~POLLIN;
+                    }
+                }
+            }
+        }
+
+        logger_for_each(logger, logger_list) {
+            unsigned int hdr_size;
+            struct log_list *entry;
+            int diff;
+
+            if (!(*(logger->revents) & POLLIN)) {
+                continue;
+            }
+
+            memset(logger_list->entry.buf, 0, sizeof(struct log_msg));
+            /* NOTE: driver guarantees we read exactly one full entry */
+            result = read(logger->fd, logger_list->entry.buf,
+                          LOGGER_ENTRY_MAX_LEN);
+            if (result <= 0) {
+                if (!result) {
+                    error = EIO;
+                } else if (errno != EINTR) {
+                    error = errno;
+                }
+                continue;
+            }
+
+            if (logger_list->pid
+                    && (logger_list->pid != logger_list->entry.entry.pid)) {
+                continue;
+            }
+
+            hdr_size = logger_list->entry.entry.hdr_size;
+            if (!hdr_size) {
+                hdr_size = sizeof(logger_list->entry.entry_v1);
+            }
+
+            if ((hdr_size > sizeof(struct log_msg))
+                    || (logger_list->entry.entry.len
+                        > sizeof(logger_list->entry.buf) - hdr_size)
+                    || (logger_list->entry.entry.len != result - hdr_size)) {
+                error = EINVAL;
+                continue;
+            }
+
+            /* Promote entry to v3 format */
+            diff = sizeof(logger_list->entry.entry_v3) - hdr_size;
+            if (diff > 0) {
+                if (logger_list->entry.entry.len
+                        > sizeof(logger_list->entry.buf) - hdr_size - diff) {
+                    error = EINVAL;
+                    continue;
+                }
+                result += diff;
+                memmove(logger_list->entry.buf + hdr_size + diff,
+                        logger_list->entry.buf + hdr_size,
+                        logger_list->entry.entry.len + 1);
+                memset(logger_list->entry.buf + hdr_size, 0, diff);
+                logger_list->entry.entry.hdr_size = hdr_size + diff;
+            }
+            logger_list->entry.entry.lid = logger->id;
+
+            /* speedup: If not tail, and only one list, send directly */
+            if (!logger_list->tail
+                    && (list_head(&logger_list->node)
+                        == list_tail(&logger_list->node))) {
+                ret = result;
+                memcpy(log_msg->buf, logger_list->entry.buf, result + 1);
+                break;
+            }
+
+            entry = malloc(sizeof(*entry) - sizeof(entry->entry) + result + 1);
+
+            if (!entry) {
+                logger_list->valid_entry = true;
+                error = ENOMEM;
+                break;
+            }
+
+            logger_list->queued_lines++;
+
+            memcpy(entry->entry.buf, logger_list->entry.buf, result);
+            entry->entry.buf[result] = '\0';
+            list_add_tail(&logger->log_list, &entry->node);
+        }
+
+        if (ret <= 0) {
+try_flush:
+            ret = android_logger_list_flush(logger_list, log_msg);
+        }
+    }
+
+    free(pollfds);
+
+flush:
+    if (error) {
+        logger_list->flush = true;
+    }
+
+    if (ret <= 0) {
+        ret = android_logger_list_flush(logger_list, log_msg);
+
+        if (!ret && logger_list->valid_entry) {
+            ret = logger_list->entry.entry.hdr_size;
+            if (!ret) {
+                ret = sizeof(logger_list->entry.entry_v1);
+            }
+            ret += logger_list->entry.entry.len;
+
+            memcpy(log_msg->buf, logger_list->entry.buf,
+                   sizeof(struct log_msg));
+            logger_list->valid_entry = false;
+        }
+    }
+
+done:
+    if (logger_list->error) {
+        error = logger_list->error;
+    }
+    if (error) {
+        logger_list->error = error;
+        if (!ret) {
+            ret = -error;
+        }
+    }
+    return ret;
+}
+
+/* Close all the logs */
+void android_logger_list_free(struct logger_list *logger_list)
+{
+    if (logger_list == NULL) {
+        return;
+    }
+
+    while (!list_empty(&logger_list->node)) {
+        struct listnode *node = list_head(&logger_list->node);
+        struct logger *logger = node_to_item(node, struct logger, node);
+        android_logger_free(logger);
+    }
+
+    free(logger_list);
+}
diff --git a/liblog/log_time.cpp b/liblog/log_time.cpp
new file mode 100644
index 0000000..755c2d9
--- /dev/null
+++ b/liblog/log_time.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2014 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 <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/cdefs.h>
+
+#include <log/log_read.h>
+
+const char log_time::default_format[] = "%m-%d %H:%M:%S.%3q";
+const timespec log_time::EPOCH = { 0, 0 };
+
+// Add %#q for fractional seconds to standard strptime function
+
+char *log_time::strptime(const char *s, const char *format) {
+    time_t now;
+#ifdef __linux__
+    *this = log_time(CLOCK_REALTIME);
+    now = tv_sec;
+#else
+    time(&now);
+    tv_sec = now;
+    tv_nsec = 0;
+#endif
+
+    struct tm *ptm;
+#if (defined(HAVE_LOCALTIME_R))
+    struct tm tmBuf;
+    ptm = localtime_r(&now, &tmBuf);
+#else
+    ptm = localtime(&now);
+#endif
+
+    char fmt[strlen(format) + 1];
+    strcpy(fmt, format);
+
+    char *ret = const_cast<char *> (s);
+    char *cp;
+    for (char *f = cp = fmt; ; ++cp) {
+        if (!*cp) {
+            if (f != cp) {
+                ret = ::strptime(ret, f, ptm);
+            }
+            break;
+        }
+        if (*cp != '%') {
+            continue;
+        }
+        char *e = cp;
+        ++e;
+#if (defined(__BIONIC__))
+        if (*e == 's') {
+            *cp = '\0';
+            if (*f) {
+                ret = ::strptime(ret, f, ptm);
+                if (!ret) {
+                    break;
+                }
+            }
+            tv_sec = 0;
+            while (isdigit(*ret)) {
+                tv_sec = tv_sec * 10 + *ret - '0';
+                ++ret;
+            }
+            now = tv_sec;
+#if (defined(HAVE_LOCALTIME_R))
+            ptm = localtime_r(&now, &tmBuf);
+#else
+            ptm = localtime(&now);
+#endif
+        } else
+#endif
+        {
+            unsigned num = 0;
+            while (isdigit(*e)) {
+                num = num * 10 + *e - '0';
+                ++e;
+            }
+            if (*e != 'q') {
+                continue;
+            }
+            *cp = '\0';
+            if (*f) {
+                ret = ::strptime(ret, f, ptm);
+                if (!ret) {
+                    break;
+                }
+            }
+            unsigned long mul = NS_PER_SEC;
+            if (num == 0) {
+                num = INT_MAX;
+            }
+            tv_nsec = 0;
+            while (isdigit(*ret) && num && (mul > 1)) {
+                --num;
+                mul /= 10;
+                tv_nsec = tv_nsec + (*ret - '0') * mul;
+                ++ret;
+            }
+        }
+        f = cp = e;
+        ++f;
+    }
+
+    if (ret) {
+        tv_sec = mktime(ptm);
+        return ret;
+    }
+
+    // Upon error, place a known value into the class, the current time.
+#ifdef __linux__
+    *this = log_time(CLOCK_REALTIME);
+#else
+    time(&now);
+    tv_sec = now;
+    tv_nsec = 0;
+#endif
+    return ret;
+}
+
+log_time log_time::operator-= (const timespec &T) {
+    // No concept of negative time, clamp to EPOCH
+    if (*this <= T) {
+        return *this = EPOCH;
+    }
+
+    if (this->tv_nsec < (unsigned long int)T.tv_nsec) {
+        --this->tv_sec;
+        this->tv_nsec = NS_PER_SEC + this->tv_nsec - T.tv_nsec;
+    } else {
+        this->tv_nsec -= T.tv_nsec;
+    }
+    this->tv_sec -= T.tv_sec;
+
+    return *this;
+}
+
+log_time log_time::operator-= (const log_time &T) {
+    // No concept of negative time, clamp to EPOCH
+    if (*this <= T) {
+        return *this = EPOCH;
+    }
+
+    if (this->tv_nsec < T.tv_nsec) {
+        --this->tv_sec;
+        this->tv_nsec = NS_PER_SEC + this->tv_nsec - T.tv_nsec;
+    } else {
+        this->tv_nsec -= T.tv_nsec;
+    }
+    this->tv_sec -= T.tv_sec;
+
+    return *this;
+}
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index 5766f8c..3171c78 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -13,41 +13,34 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <time.h>
-#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
 #ifdef HAVE_PTHREADS
 #include <pthread.h>
 #endif
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
 #include <stdarg.h>
-#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <sys/stat.h>
+#include <sys/types.h>
+#if (FAKE_LOG_DEVICE == 0)
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif
+#include <time.h>
+#include <unistd.h>
 
-#include <log/logger.h>
 #include <log/logd.h>
-#include <log/log.h>
-
-#define LOGGER_LOG_MAIN		"log/main"
-#define LOGGER_LOG_RADIO	"log/radio"
-#define LOGGER_LOG_EVENTS	"log/events"
-#define LOGGER_LOG_SYSTEM	"log/system"
+#include <log/logger.h>
+#include <log/log_read.h>
+#include <private/android_filesystem_config.h>
 
 #define LOG_BUF_SIZE 1024
 
 #if FAKE_LOG_DEVICE
-// This will be defined when building for the host.
+/* This will be defined when building for the host. */
 #include "fake_log_device.h"
-#define log_open(pathname, flags) fakeLogOpen(pathname, flags)
-#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) | O_CLOEXEC)
-#define log_writev(filedes, vector, count) writev(filedes, vector, count)
-#define log_close(filedes) close(filedes)
 #endif
 
 static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);
@@ -56,13 +49,20 @@
 static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
 #endif
 
-#define UNUSED  __attribute__((__unused__))
+#ifndef __unused
+#define __unused  __attribute__((__unused__))
+#endif
 
-static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1 };
+#if FAKE_LOG_DEVICE
+#define WEAK __attribute__((weak))
+static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1 };
+#else
+static int logd_fd = -1;
+#endif
 
 /*
  * This is used by the C++ code to decide if it should write logs through
- * the C code.  Basically, if /dev/log/... is available, we're running in
+ * the C code.  Basically, if /dev/socket/logd is available, we're running in
  * the simulator rather than a desktop tool and want to use the device.
  */
 static enum {
@@ -71,7 +71,7 @@
 int __android_log_dev_available(void)
 {
     if (g_log_status == kLogUninitialized) {
-        if (access("/dev/"LOGGER_LOG_MAIN, W_OK) == 0)
+        if (access("/dev/socket/logdw", W_OK) == 0)
             g_log_status = kLogAvailable;
         else
             g_log_status = kLogNotAvailable;
@@ -80,30 +80,205 @@
     return (g_log_status == kLogAvailable);
 }
 
-static int __write_to_log_null(log_id_t log_fd UNUSED, struct iovec *vec UNUSED,
-        size_t nr UNUSED)
+#if !FAKE_LOG_DEVICE
+/* give up, resources too limited */
+static int __write_to_log_null(log_id_t log_fd __unused, struct iovec *vec __unused,
+                               size_t nr __unused)
 {
     return -1;
 }
+#endif
+
+/* log_init_lock assumed */
+static int __write_to_log_initialize()
+{
+    int i, ret = 0;
+
+#if FAKE_LOG_DEVICE
+    for (i = 0; i < LOG_ID_MAX; i++) {
+        char buf[sizeof("/dev/log_system")];
+        snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i));
+        log_fds[i] = fakeLogOpen(buf, O_WRONLY);
+    }
+#else
+    if (logd_fd >= 0) {
+        i = logd_fd;
+        logd_fd = -1;
+        close(i);
+    }
+
+    i = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+    if (i < 0) {
+        ret = -errno;
+        write_to_log = __write_to_log_null;
+    } else if (fcntl(i, F_SETFL, O_NONBLOCK) < 0) {
+        ret = -errno;
+        close(i);
+        i = -1;
+        write_to_log = __write_to_log_null;
+    } else {
+        struct sockaddr_un un;
+        memset(&un, 0, sizeof(struct sockaddr_un));
+        un.sun_family = AF_UNIX;
+        strcpy(un.sun_path, "/dev/socket/logdw");
+
+        if (connect(i, (struct sockaddr *)&un, sizeof(struct sockaddr_un)) < 0) {
+            ret = -errno;
+            close(i);
+            i = -1;
+        }
+    }
+    logd_fd = i;
+#endif
+
+    return ret;
+}
 
 static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr)
 {
     ssize_t ret;
+#if FAKE_LOG_DEVICE
     int log_fd;
 
     if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) {
         log_fd = log_fds[(int)log_id];
     } else {
-        return EBADF;
+        return -EBADF;
+    }
+    do {
+        ret = fakeLogWritev(log_fd, vec, nr);
+        if (ret < 0) {
+            ret = -errno;
+        }
+    } while (ret == -EINTR);
+#else
+    static const unsigned header_length = 3;
+    struct iovec newVec[nr + header_length];
+    typeof_log_id_t log_id_buf;
+    uint16_t tid;
+    struct timespec ts;
+    log_time realtime_ts;
+    size_t i, payload_size;
+    static uid_t last_uid = AID_ROOT; /* logd *always* starts up as AID_ROOT */
+
+    if (last_uid == AID_ROOT) { /* have we called to get the UID yet? */
+        last_uid = getuid();
+    }
+    if (last_uid == AID_LOGD) { /* logd, after initialization and priv drop */
+        /*
+         * ignore log messages we send to ourself (logd).
+         * Such log messages are often generated by libraries we depend on
+         * which use standard Android logging.
+         */
+        return 0;
     }
 
-    do {
-        ret = log_writev(log_fd, vec, nr);
-    } while (ret < 0 && errno == EINTR);
+    if (logd_fd < 0) {
+        return -EBADF;
+    }
+
+    /*
+     *  struct {
+     *      // what we provide
+     *      typeof_log_id_t  log_id;
+     *      u16              tid;
+     *      log_time         realtime;
+     *      // caller provides
+     *      union {
+     *          struct {
+     *              char     prio;
+     *              char     payload[];
+     *          } string;
+     *          struct {
+     *              uint32_t tag
+     *              char     payload[];
+     *          } binary;
+     *      };
+     *  };
+     */
+
+    clock_gettime(CLOCK_REALTIME, &ts);
+    realtime_ts.tv_sec = ts.tv_sec;
+    realtime_ts.tv_nsec = ts.tv_nsec;
+
+    log_id_buf = log_id;
+    tid = gettid();
+
+    newVec[0].iov_base   = (unsigned char *) &log_id_buf;
+    newVec[0].iov_len    = sizeof_log_id_t;
+    newVec[1].iov_base   = (unsigned char *) &tid;
+    newVec[1].iov_len    = sizeof(tid);
+    newVec[2].iov_base   = (unsigned char *) &realtime_ts;
+    newVec[2].iov_len    = sizeof(log_time);
+
+    for (payload_size = 0, i = header_length; i < nr + header_length; i++) {
+        newVec[i].iov_base = vec[i - header_length].iov_base;
+        payload_size += newVec[i].iov_len = vec[i - header_length].iov_len;
+
+        if (payload_size > LOGGER_ENTRY_MAX_PAYLOAD) {
+            newVec[i].iov_len -= payload_size - LOGGER_ENTRY_MAX_PAYLOAD;
+            if (newVec[i].iov_len) {
+                ++i;
+            }
+            break;
+        }
+    }
+
+    /*
+     * The write below could be lost, but will never block.
+     *
+     * ENOTCONN occurs if logd dies.
+     * EAGAIN occurs if logd is overloaded.
+     */
+    ret = writev(logd_fd, newVec, i);
+    if (ret < 0) {
+        ret = -errno;
+        if (ret == -ENOTCONN) {
+#ifdef HAVE_PTHREADS
+            pthread_mutex_lock(&log_init_lock);
+#endif
+            ret = __write_to_log_initialize();
+#ifdef HAVE_PTHREADS
+            pthread_mutex_unlock(&log_init_lock);
+#endif
+
+            if (ret < 0) {
+                return ret;
+            }
+
+            ret = writev(logd_fd, newVec, nr + header_length);
+            if (ret < 0) {
+                ret = -errno;
+            }
+        }
+    }
+
+    if (ret > (ssize_t)(sizeof_log_id_t + sizeof(tid) + sizeof(log_time))) {
+        ret -= sizeof_log_id_t + sizeof(tid) + sizeof(log_time);
+    }
+#endif
 
     return ret;
 }
 
+#if FAKE_LOG_DEVICE
+static const char *LOG_NAME[LOG_ID_MAX] = {
+    [LOG_ID_MAIN] = "main",
+    [LOG_ID_RADIO] = "radio",
+    [LOG_ID_EVENTS] = "events",
+    [LOG_ID_SYSTEM] = "system",
+    [LOG_ID_CRASH] = "crash"
+};
+
+const WEAK char *android_log_id_to_name(log_id_t log_id)
+{
+    if (log_id >= LOG_ID_MAX) {
+        log_id = LOG_ID_MAIN;
+    }
+    return LOG_NAME[log_id];
+}
+#endif
+
 static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
 {
 #ifdef HAVE_PTHREADS
@@ -111,27 +286,17 @@
 #endif
 
     if (write_to_log == __write_to_log_init) {
-        log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY);
-        log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY);
-        log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY);
-        log_fds[LOG_ID_SYSTEM] = log_open("/dev/"LOGGER_LOG_SYSTEM, O_WRONLY);
+        int ret;
+
+        ret = __write_to_log_initialize();
+        if (ret < 0) {
+#ifdef HAVE_PTHREADS
+            pthread_mutex_unlock(&log_init_lock);
+#endif
+            return ret;
+        }
 
         write_to_log = __write_to_log_kernel;
-
-        if (log_fds[LOG_ID_MAIN] < 0 || log_fds[LOG_ID_RADIO] < 0 ||
-                log_fds[LOG_ID_EVENTS] < 0) {
-            log_close(log_fds[LOG_ID_MAIN]);
-            log_close(log_fds[LOG_ID_RADIO]);
-            log_close(log_fds[LOG_ID_EVENTS]);
-            log_fds[LOG_ID_MAIN] = -1;
-            log_fds[LOG_ID_RADIO] = -1;
-            log_fds[LOG_ID_EVENTS] = -1;
-            write_to_log = __write_to_log_null;
-        }
-
-        if (log_fds[LOG_ID_SYSTEM] < 0) {
-            log_fds[LOG_ID_SYSTEM] = log_fds[LOG_ID_MAIN];
-        }
     }
 
 #ifdef HAVE_PTHREADS
@@ -161,11 +326,18 @@
         !strcmp(tag, "PHONE") ||
         !strcmp(tag, "SMS")) {
             log_id = LOG_ID_RADIO;
-            // Inform third party apps/ril/radio.. to use Rlog or RLOG
+            /* 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;
     }
 
+#if __BIONIC__
+    if (prio == ANDROID_LOG_FATAL) {
+        extern void __android_set_abort_message(const char*);
+        __android_set_abort_message(msg);
+    }
+#endif
+
     vec[0].iov_base   = (unsigned char *) &prio;
     vec[0].iov_len    = 1;
     vec[1].iov_base   = (void *) tag;
@@ -196,7 +368,7 @@
         !strcmp(tag, "PHONE") ||
         !strcmp(tag, "SMS"))) {
             bufID = LOG_ID_RADIO;
-            // Inform third party apps/ril/radio.. to use Rlog or RLOG
+            /* 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;
     }
@@ -266,8 +438,8 @@
     }
 
     __android_log_write(ANDROID_LOG_FATAL, tag, buf);
-
     __builtin_trap(); /* trap so we have a chance to debug the situation */
+    /* NOTREACHED */
 }
 
 int __android_log_bwrite(int32_t tag, const void *payload, size_t len)
@@ -288,7 +460,7 @@
  * handy if we just want to dump an integer into the log.
  */
 int __android_log_btwrite(int32_t tag, char type, const void *payload,
-    size_t len)
+                          size_t len)
 {
     struct iovec vec[3];
 
@@ -301,3 +473,25 @@
 
     return write_to_log(LOG_ID_EVENTS, vec, 3);
 }
+
+/*
+ * Like __android_log_bwrite, but used for writing strings to the
+ * event log.
+ */
+int __android_log_bswrite(int32_t tag, const char *payload)
+{
+    struct iovec vec[4];
+    char type = EVENT_TYPE_STRING;
+    uint32_t len = strlen(payload);
+
+    vec[0].iov_base = &tag;
+    vec[0].iov_len = sizeof(tag);
+    vec[1].iov_base = &type;
+    vec[1].iov_len = sizeof(type);
+    vec[2].iov_base = &len;
+    vec[2].iov_len = sizeof(len);
+    vec[3].iov_base = (void*)payload;
+    vec[3].iov_len = len;
+
+    return write_to_log(LOG_ID_EVENTS, vec, 4);
+}
diff --git a/liblog/logd_write_kern.c b/liblog/logd_write_kern.c
new file mode 100644
index 0000000..1ed5ecf
--- /dev/null
+++ b/liblog/logd_write_kern.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2007-2014 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>
+#ifdef HAVE_PTHREADS
+#include <pthread.h>
+#endif
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <log/log.h>
+#include <log/logd.h>
+#include <log/logger.h>
+
+#define LOGGER_LOG_MAIN		"log/main"
+#define LOGGER_LOG_RADIO	"log/radio"
+#define LOGGER_LOG_EVENTS	"log/events"
+#define LOGGER_LOG_SYSTEM	"log/system"
+
+#define LOG_BUF_SIZE 1024
+
+#if FAKE_LOG_DEVICE
+/* This will be defined when building for the host. */
+#include "fake_log_device.h"
+#define log_open(pathname, flags) fakeLogOpen(pathname, flags)
+#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) | O_CLOEXEC)
+#define log_writev(filedes, vector, count) writev(filedes, vector, count)
+#define log_close(filedes) close(filedes)
+#endif
+
+static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);
+static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;
+#ifdef HAVE_PTHREADS
+static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+#ifndef __unused
+#define __unused  __attribute__((__unused__))
+#endif
+
+static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1 };
+
+/*
+ * This is used by the C++ code to decide if it should write logs through
+ * the C code.  Basically, if /dev/log/... is available, we're running in
+ * the simulator rather than a desktop tool and want to use the device.
+ */
+static enum {
+    kLogUninitialized, kLogNotAvailable, kLogAvailable
+} g_log_status = kLogUninitialized;
+int __android_log_dev_available(void)
+{
+    if (g_log_status == kLogUninitialized) {
+        if (access("/dev/"LOGGER_LOG_MAIN, W_OK) == 0)
+            g_log_status = kLogAvailable;
+        else
+            g_log_status = kLogNotAvailable;
+    }
+
+    return (g_log_status == kLogAvailable);
+}
+
+static int __write_to_log_null(log_id_t log_fd __unused, struct iovec *vec __unused,
+                               size_t nr __unused)
+{
+    return -1;
+}
+
+static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr)
+{
+    ssize_t ret;
+    int log_fd;
+
+    if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) {
+        if (log_id == LOG_ID_CRASH) {
+            log_id = LOG_ID_MAIN;
+        }
+        log_fd = log_fds[(int)log_id];
+    } else {
+        return -EBADF;
+    }
+
+    do {
+        ret = log_writev(log_fd, vec, nr);
+        if (ret < 0) {
+            ret = -errno;
+        }
+    } while (ret == -EINTR);
+
+    return ret;
+}
+
+static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
+{
+#ifdef HAVE_PTHREADS
+    pthread_mutex_lock(&log_init_lock);
+#endif
+
+    if (write_to_log == __write_to_log_init) {
+        log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY);
+        log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY);
+        log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY);
+        log_fds[LOG_ID_SYSTEM] = log_open("/dev/"LOGGER_LOG_SYSTEM, O_WRONLY);
+
+        write_to_log = __write_to_log_kernel;
+
+        if (log_fds[LOG_ID_MAIN] < 0 || log_fds[LOG_ID_RADIO] < 0 ||
+                log_fds[LOG_ID_EVENTS] < 0) {
+            log_close(log_fds[LOG_ID_MAIN]);
+            log_close(log_fds[LOG_ID_RADIO]);
+            log_close(log_fds[LOG_ID_EVENTS]);
+            log_fds[LOG_ID_MAIN] = -1;
+            log_fds[LOG_ID_RADIO] = -1;
+            log_fds[LOG_ID_EVENTS] = -1;
+            write_to_log = __write_to_log_null;
+        }
+
+        if (log_fds[LOG_ID_SYSTEM] < 0) {
+            log_fds[LOG_ID_SYSTEM] = log_fds[LOG_ID_MAIN];
+        }
+    }
+
+#ifdef HAVE_PTHREADS
+    pthread_mutex_unlock(&log_init_lock);
+#endif
+
+    return write_to_log(log_id, vec, nr);
+}
+
+int __android_log_write(int prio, const char *tag, const char *msg)
+{
+    struct iovec vec[3];
+    log_id_t log_id = LOG_ID_MAIN;
+    char tmp_tag[32];
+
+    if (!tag)
+        tag = "";
+
+    /* XXX: This needs to go! */
+    if (!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") ||
+        !strcmp(tag, "GSM") ||
+        !strcmp(tag, "STK") ||
+        !strcmp(tag, "CDMA") ||
+        !strcmp(tag, "PHONE") ||
+        !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;
+    }
+
+#if __BIONIC__
+    if (prio == ANDROID_LOG_FATAL) {
+        extern void __android_set_abort_message(const char*);
+        __android_set_abort_message(msg);
+    }
+#endif
+
+    vec[0].iov_base   = (unsigned char *) &prio;
+    vec[0].iov_len    = 1;
+    vec[1].iov_base   = (void *) tag;
+    vec[1].iov_len    = strlen(tag) + 1;
+    vec[2].iov_base   = (void *) msg;
+    vec[2].iov_len    = strlen(msg) + 1;
+
+    return write_to_log(log_id, vec, 3);
+}
+
+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 ((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") ||
+        !strcmp(tag, "GSM") ||
+        !strcmp(tag, "STK") ||
+        !strcmp(tag, "CDMA") ||
+        !strcmp(tag, "PHONE") ||
+        !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;
+    vec[1].iov_base   = (void *) tag;
+    vec[1].iov_len    = strlen(tag) + 1;
+    vec[2].iov_base   = (void *) msg;
+    vec[2].iov_len    = strlen(msg) + 1;
+
+    return write_to_log(bufID, vec, 3);
+}
+
+int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap)
+{
+    char buf[LOG_BUF_SIZE];
+
+    vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+
+    return __android_log_write(prio, tag, buf);
+}
+
+int __android_log_print(int prio, const char *tag, const char *fmt, ...)
+{
+    va_list ap;
+    char buf[LOG_BUF_SIZE];
+
+    va_start(ap, fmt);
+    vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+    va_end(ap);
+
+    return __android_log_write(prio, tag, buf);
+}
+
+int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...)
+{
+    va_list ap;
+    char buf[LOG_BUF_SIZE];
+
+    va_start(ap, fmt);
+    vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+    va_end(ap);
+
+    return __android_log_buf_write(bufID, prio, tag, buf);
+}
+
+void __android_log_assert(const char *cond, const char *tag,
+                          const char *fmt, ...)
+{
+    char buf[LOG_BUF_SIZE];
+
+    if (fmt) {
+        va_list ap;
+        va_start(ap, fmt);
+        vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+        va_end(ap);
+    } else {
+        /* Msg not provided, log condition.  N.B. Do not use cond directly as
+         * format string as it could contain spurious '%' syntax (e.g.
+         * "%d" in "blocks%devs == 0").
+         */
+        if (cond)
+            snprintf(buf, LOG_BUF_SIZE, "Assertion failed: %s", cond);
+        else
+            strcpy(buf, "Unspecified assertion failed");
+    }
+
+    __android_log_write(ANDROID_LOG_FATAL, tag, buf);
+    __builtin_trap(); /* trap so we have a chance to debug the situation */
+    /* NOTREACHED */
+}
+
+int __android_log_bwrite(int32_t tag, const void *payload, size_t len)
+{
+    struct iovec vec[2];
+
+    vec[0].iov_base = &tag;
+    vec[0].iov_len = sizeof(tag);
+    vec[1].iov_base = (void*)payload;
+    vec[1].iov_len = len;
+
+    return write_to_log(LOG_ID_EVENTS, vec, 2);
+}
+
+/*
+ * Like __android_log_bwrite, but takes the type as well.  Doesn't work
+ * for the general case where we're generating lists of stuff, but very
+ * handy if we just want to dump an integer into the log.
+ */
+int __android_log_btwrite(int32_t tag, char type, const void *payload,
+                          size_t len)
+{
+    struct iovec vec[3];
+
+    vec[0].iov_base = &tag;
+    vec[0].iov_len = sizeof(tag);
+    vec[1].iov_base = &type;
+    vec[1].iov_len = sizeof(type);
+    vec[2].iov_base = (void*)payload;
+    vec[2].iov_len = len;
+
+    return write_to_log(LOG_ID_EVENTS, vec, 3);
+}
+
+/*
+ * Like __android_log_bwrite, but used for writing strings to the
+ * event log.
+ */
+int __android_log_bswrite(int32_t tag, const char *payload)
+{
+    struct iovec vec[4];
+    char type = EVENT_TYPE_STRING;
+    uint32_t len = strlen(payload);
+
+    vec[0].iov_base = &tag;
+    vec[0].iov_len = sizeof(tag);
+    vec[1].iov_base = &type;
+    vec[1].iov_len = sizeof(type);
+    vec[2].iov_base = &len;
+    vec[2].iov_len = sizeof(len);
+    vec[3].iov_base = (void*)payload;
+    vec[3].iov_len = len;
+
+    return write_to_log(LOG_ID_EVENTS, vec, 4);
+}
diff --git a/liblog/logprint.c b/liblog/logprint.c
index a7480d5..08e830a 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -17,14 +17,14 @@
 
 #define _GNU_SOURCE /* for asprintf */
 
-#include <ctype.h>
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <assert.h>
 #include <arpa/inet.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
 #include <log/logd.h>
 #include <log/logprint.h>
@@ -52,15 +52,7 @@
     return p_ret;
 }
 
-static void filterinfo_free(FilterInfo *p_info)
-{
-    if (p_info == NULL) {
-        return;
-    }
-
-    free(p_info->mTag);
-    p_info->mTag = NULL;
-}
+/* balance to above, filterinfo_free left unimplemented */
 
 /*
  * Note: also accepts 0-9 priorities
@@ -139,23 +131,6 @@
     return p_format->global_pri;
 }
 
-/** for debugging */
-static void dumpFilters(AndroidLogFormat *p_format)
-{
-    FilterInfo *p_fi;
-
-    for (p_fi = p_format->filters ; p_fi != NULL ; p_fi = p_fi->p_next) {
-        char cPri = filterPriToChar(p_fi->mPri);
-        if (p_fi->mPri == ANDROID_LOG_DEFAULT) {
-            cPri = filterPriToChar(p_format->global_pri);
-        }
-        fprintf(stderr,"%s:%c\n", p_fi->mTag, cPri);
-    }
-
-    fprintf(stderr,"*:%c\n", filterPriToChar(p_format->global_pri));
-
-}
-
 /**
  * returns 1 if this log line should be printed based on its priority
  * and tag, and 0 if it should not
@@ -234,7 +209,6 @@
 int android_log_addFilterRule(AndroidLogFormat *p_format,
         const char *filterExpression)
 {
-    size_t i=0;
     size_t tagNameLength;
     android_LogPriority pri = ANDROID_LOG_DEFAULT;
 
@@ -718,7 +692,6 @@
 #endif
     struct tm* ptm;
     char timeBuf[32];
-    char headerBuf[128];
     char prefixBuf[128], suffixBuf[128];
     char priChar;
     int prefixSuffixIsHeaderFooter = 0;
@@ -817,7 +790,6 @@
     /* the following code is tragically unreadable */
 
     size_t numLines;
-    size_t i;
     char *p;
     size_t bufferSize;
     const char *pm;
@@ -938,88 +910,3 @@
 
     return ret;
 }
-
-
-
-void logprint_run_tests()
-{
-#if 0
-
-    fprintf(stderr, "tests disabled\n");
-
-#else
-
-    int err;
-    const char *tag;
-    AndroidLogFormat *p_format;
-
-    p_format = android_log_format_new();
-
-    fprintf(stderr, "running tests\n");
-
-    tag = "random";
-
-    android_log_addFilterRule(p_format,"*:i");
-
-    assert (ANDROID_LOG_INFO == filterPriForTag(p_format, "random"));
-    assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
-    android_log_addFilterRule(p_format, "*");
-    assert (ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
-    assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
-    android_log_addFilterRule(p_format, "*:v");
-    assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
-    assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
-    android_log_addFilterRule(p_format, "*:i");
-    assert (ANDROID_LOG_INFO == filterPriForTag(p_format, "random"));
-    assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
-
-    android_log_addFilterRule(p_format, "random");
-    assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
-    assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
-    android_log_addFilterRule(p_format, "random:v");
-    assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
-    assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
-    android_log_addFilterRule(p_format, "random:d");
-    assert (ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
-    assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
-    android_log_addFilterRule(p_format, "random:w");
-    assert (ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
-    assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
-
-    android_log_addFilterRule(p_format, "crap:*");
-    assert (ANDROID_LOG_VERBOSE== filterPriForTag(p_format, "crap"));
-    assert(android_log_shouldPrintLine(p_format, "crap", ANDROID_LOG_VERBOSE) > 0);
-
-    // invalid expression
-    err = android_log_addFilterRule(p_format, "random:z");
-    assert (err < 0);
-    assert (ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
-    assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
-
-    // Issue #550946
-    err = android_log_addFilterString(p_format, " ");
-    assert(err == 0);
-    assert(ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
-
-    // note trailing space
-    err = android_log_addFilterString(p_format, "*:s random:d ");
-    assert(err == 0);
-    assert(ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
-
-    err = android_log_addFilterString(p_format, "*:s random:z");
-    assert(err < 0);
-
-
-#if 0
-    char *ret;
-    char defaultBuffer[512];
-
-    ret = android_log_formatLogLine(p_format,
-        defaultBuffer, sizeof(defaultBuffer), 0, ANDROID_LOG_ERROR, 123,
-        123, 123, "random", "nofile", strlen("Hello"), "Hello", NULL);
-#endif
-
-
-    fprintf(stderr, "tests complete\n");
-#endif
-}
diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk
index db06cf7..255dc2e 100644
--- a/liblog/tests/Android.mk
+++ b/liblog/tests/Android.mk
@@ -32,7 +32,7 @@
 
 benchmark_src_files := \
     benchmark_main.cpp \
-    liblog_benchmark.cpp \
+    liblog_benchmark.cpp
 
 # Build benchmarks for the device. Run with:
 #   adb shell liblog-benchmarks
@@ -59,10 +59,22 @@
     -g \
     -Wall -Wextra \
     -Werror \
-    -fno-builtin \
+    -fno-builtin
 
 test_src_files := \
-    liblog_test.cpp \
+    liblog_test.cpp
+
+# to prevent breaking the build if bionic not relatively visible to us
+ifneq ($(wildcard $(LOCAL_PATH)/../../../../bionic/libc/bionic/libc_logging.cpp),)
+
+test_src_files += \
+    libc_test.cpp
+
+ifndef ($(TARGET_USES_LOGD),false)
+test_c_flags += -DTARGET_USES_LOGD
+endif
+
+endif
 
 # Build tests for the device (with .so). Run with:
 #   adb shell /data/nativetest/liblog-unit-tests/liblog-unit-tests
@@ -71,7 +83,6 @@
 LOCAL_MODULE_TAGS := $(test_tags)
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += $(test_c_flags)
-LOCAL_LDLIBS := -lpthread
 LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_SRC_FILES := $(test_src_files)
 include $(BUILD_NATIVE_TEST)
diff --git a/liblog/tests/benchmark_main.cpp b/liblog/tests/benchmark_main.cpp
index 02df460..090394c 100644
--- a/liblog/tests/benchmark_main.cpp
+++ b/liblog/tests/benchmark_main.cpp
@@ -16,6 +16,7 @@
 
 #include <benchmark.h>
 
+#include <inttypes.h>
 #include <regex.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -158,10 +159,10 @@
     sdev = (sqrt((double)nXvariance) / gBenchmarkNum / gBenchmarkNum) + 0.5;
   }
   if (mean > (10000 * sdev)) {
-    printf("%-25s %10llu %10llu%s\n", full_name,
+    printf("%-25s %10" PRIu64 " %10" PRIu64 "%s\n", full_name,
             static_cast<uint64_t>(iterations), mean, throughput);
   } else {
-    printf("%-25s %10llu %10llu(\317\203%llu)%s\n", full_name,
+    printf("%-25s %10" PRIu64 " %10" PRIu64 "(\317\203%" PRIu64 ")%s\n", full_name,
            static_cast<uint64_t>(iterations), mean, sdev, throughput);
   }
   fflush(stdout);
diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp
new file mode 100644
index 0000000..9839729
--- /dev/null
+++ b/liblog/tests/libc_test.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2014 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 <fcntl.h>
+#include <sys/cdefs.h>
+
+#include <gtest/gtest.h>
+
+// Should be in bionic test suite, *but* we are using liblog to confirm
+// end-to-end logging, so let the overly cute oedipus complex begin ...
+#include "../../../../bionic/libc/bionic/libc_logging.cpp" // not Standalone
+#define _ANDROID_LOG_H // Priorities redefined
+#define _LIBS_LOG_LOG_H // log ids redefined
+typedef unsigned char log_id_t; // log_id_t missing as a result
+#ifdef TARGET_USES_LOGD
+#define _LIBS_LOG_LOG_READ_H // log_time redefined
+#endif
+
+#include <log/log.h>
+#include <log/logger.h>
+#include <log/log_read.h>
+
+TEST(libc, __libc_android_log_event_int) {
+    struct logger_list *logger_list;
+
+    pid_t pid = getpid();
+
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+        LOG_ID_EVENTS, O_RDONLY | O_NDELAY, 1000, pid)));
+
+    struct timespec ts;
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+    int value = ts.tv_nsec;
+
+    __libc_android_log_event_int(0, value);
+    usleep(1000000);
+
+    int count = 0;
+
+    for (;;) {
+        log_msg log_msg;
+        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+            break;
+        }
+
+        ASSERT_EQ(log_msg.entry.pid, pid);
+
+        if ((log_msg.entry.len != (4 + 1 + 4))
+         || ((int)log_msg.id() != LOG_ID_EVENTS)) {
+            continue;
+        }
+
+        char *eventData = log_msg.msg();
+
+        int incoming = (eventData[0] & 0xFF) |
+                      ((eventData[1] & 0xFF) << 8) |
+                      ((eventData[2] & 0xFF) << 16) |
+                      ((eventData[3] & 0xFF) << 24);
+
+        if (incoming != 0) {
+            continue;
+        }
+
+        if (eventData[4] != EVENT_TYPE_INT) {
+            continue;
+        }
+
+        incoming = (eventData[4 + 1 + 0] & 0xFF) |
+                  ((eventData[4 + 1 + 1] & 0xFF) << 8) |
+                  ((eventData[4 + 1 + 2] & 0xFF) << 16) |
+                  ((eventData[4 + 1 + 3] & 0xFF) << 24);
+
+        if (incoming == value) {
+            ++count;
+        }
+    }
+
+    EXPECT_EQ(1, count);
+
+    android_logger_list_close(logger_list);
+}
+
+TEST(libc, __libc_fatal_no_abort) {
+    struct logger_list *logger_list;
+
+    pid_t pid = getpid();
+
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+        (log_id_t)LOG_ID_CRASH, O_RDONLY | O_NDELAY, 1000, pid)));
+
+    char b[80];
+    struct timespec ts;
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+
+    __libc_fatal_no_abort("%u.%09u", (unsigned)ts.tv_sec, (unsigned)ts.tv_nsec);
+    snprintf(b, sizeof(b),"%u.%09u", (unsigned)ts.tv_sec, (unsigned)ts.tv_nsec);
+    usleep(1000000);
+
+    int count = 0;
+
+    for (;;) {
+        log_msg log_msg;
+        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+            break;
+        }
+
+        ASSERT_EQ(log_msg.entry.pid, pid);
+
+        if ((int)log_msg.id() != LOG_ID_CRASH) {
+            continue;
+        }
+
+        char *data = log_msg.msg();
+
+        if ((*data == ANDROID_LOG_FATAL)
+                && !strcmp(data + 1, "libc")
+                && !strcmp(data + 1 + strlen(data + 1) + 1, b)) {
+            ++count;
+        }
+    }
+
+    EXPECT_EQ(1, count);
+
+    android_logger_list_close(logger_list);
+}
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index 19406fb..549d79e 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -99,7 +99,7 @@
 }
 BENCHMARK(BM_log_overhead);
 
-static void caught_latency(int signum)
+static void caught_latency(int /*signum*/)
 {
     unsigned long long v = 0xDEADBEEFA55A5AA5ULL;
 
@@ -143,7 +143,7 @@
     for (int j = 0, i = 0; i < iters && j < 10*iters; ++i, ++j) {
         log_time ts;
         LOG_FAILURE_RETRY((
-            clock_gettime(CLOCK_REALTIME, &ts),
+            ts = log_time(CLOCK_REALTIME),
             android_btWriteLog(0, EVENT_TYPE_LONG, &ts, sizeof(ts))));
 
         for (;;) {
@@ -193,7 +193,7 @@
 }
 BENCHMARK(BM_log_latency);
 
-static void caught_delay(int signum)
+static void caught_delay(int /*signum*/)
 {
     unsigned long long v = 0xDEADBEEFA55A5AA6ULL;
 
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 9ae8f22..393e2cd 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -15,11 +15,13 @@
  */
 
 #include <fcntl.h>
+#include <inttypes.h>
 #include <signal.h>
 #include <gtest/gtest.h>
 #include <log/log.h>
 #include <log/logger.h>
 #include <log/log_read.h>
+#include <log/logprint.h>
 
 // enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
 // non-syscall libs. Since we are only using this in the emergency of
@@ -37,30 +39,30 @@
     _rc; })
 
 TEST(liblog, __android_log_buf_print) {
-    ASSERT_LT(0, __android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO,
+    EXPECT_LT(0, __android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO,
                                          "TEST__android_log_buf_print",
                                          "radio"));
     usleep(1000);
-    ASSERT_LT(0, __android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
+    EXPECT_LT(0, __android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
                                          "TEST__android_log_buf_print",
                                          "system"));
     usleep(1000);
-    ASSERT_LT(0, __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
+    EXPECT_LT(0, __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
                                          "TEST__android_log_buf_print",
                                          "main"));
     usleep(1000);
 }
 
 TEST(liblog, __android_log_buf_write) {
-    ASSERT_LT(0, __android_log_buf_write(LOG_ID_RADIO, ANDROID_LOG_INFO,
+    EXPECT_LT(0, __android_log_buf_write(LOG_ID_RADIO, ANDROID_LOG_INFO,
                                          "TEST__android_log_buf_write",
                                          "radio"));
     usleep(1000);
-    ASSERT_LT(0, __android_log_buf_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
+    EXPECT_LT(0, __android_log_buf_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
                                          "TEST__android_log_buf_write",
                                          "system"));
     usleep(1000);
-    ASSERT_LT(0, __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_INFO,
+    EXPECT_LT(0, __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_INFO,
                                          "TEST__android_log_buf_write",
                                          "main"));
     usleep(1000);
@@ -68,16 +70,16 @@
 
 TEST(liblog, __android_log_btwrite) {
     int intBuf = 0xDEADBEEF;
-    ASSERT_LT(0, __android_log_btwrite(0,
+    EXPECT_LT(0, __android_log_btwrite(0,
                                       EVENT_TYPE_INT,
                                       &intBuf, sizeof(intBuf)));
     long long longBuf = 0xDEADBEEFA55A5AA5;
-    ASSERT_LT(0, __android_log_btwrite(0,
+    EXPECT_LT(0, __android_log_btwrite(0,
                                       EVENT_TYPE_LONG,
                                       &longBuf, sizeof(longBuf)));
     usleep(1000);
     char Buf[] = "\20\0\0\0DeAdBeEfA55a5aA5";
-    ASSERT_LT(0, __android_log_btwrite(0,
+    EXPECT_LT(0, __android_log_btwrite(0,
                                       EVENT_TYPE_STRING,
                                       Buf, sizeof(Buf) - 1));
     usleep(1000);
@@ -85,8 +87,8 @@
 
 static void* ConcurrentPrintFn(void *arg) {
     int ret = __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
-                                  "TEST__android_log_print", "Concurrent %d",
-                                  reinterpret_cast<int>(arg));
+                                  "TEST__android_log_print", "Concurrent %" PRIuPTR,
+                                  reinterpret_cast<uintptr_t>(arg));
     return reinterpret_cast<void*>(ret);
 }
 
@@ -106,8 +108,9 @@
     for (i=0; i < NUM_CONCURRENT; i++) {
         void* result;
         ASSERT_EQ(0, pthread_join(t[i], &result));
-        if ((0 == ret) && (0 != reinterpret_cast<int>(result))) {
-            ret = reinterpret_cast<int>(result);
+        int this_result = reinterpret_cast<uintptr_t>(result);
+        if ((0 == ret) && (0 != this_result)) {
+            ret = this_result;
         }
     }
     ASSERT_LT(0, ret);
@@ -118,7 +121,7 @@
 
     pid_t pid = getpid();
 
-    ASSERT_EQ(0, NULL == (logger_list = android_logger_list_open(
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
         LOG_ID_EVENTS, O_RDONLY | O_NDELAY, 1000, pid)));
 
     log_time ts(CLOCK_MONOTONIC);
@@ -153,7 +156,7 @@
         }
     }
 
-    ASSERT_EQ(1, count);
+    EXPECT_EQ(1, count);
 
     android_logger_list_close(logger_list);
 }
@@ -161,7 +164,7 @@
 static unsigned signaled;
 log_time signal_time;
 
-static void caught_blocking(int signum)
+static void caught_blocking(int /*signum*/)
 {
     unsigned long long v = 0xDEADBEEFA55A0000ULL;
 
@@ -169,7 +172,7 @@
 
     ++signaled;
     if ((signal_time.tv_sec == 0) && (signal_time.tv_nsec == 0)) {
-        clock_gettime(CLOCK_MONOTONIC, &signal_time);
+        signal_time = log_time(CLOCK_MONOTONIC);
         signal_time.tv_sec += 2;
     }
 
@@ -219,7 +222,7 @@
 
     v += pid & 0xFFFF;
 
-    ASSERT_EQ(0, NULL == (logger_list = android_logger_list_open(
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
         LOG_ID_EVENTS, O_RDONLY, 1000, pid)));
 
     int count = 0;
@@ -275,13 +278,13 @@
             ++signals;
             break;
         }
-    } while (!signaled || ({log_time t(CLOCK_MONOTONIC); t < signal_time;}));
+    } while (!signaled || (log_time(CLOCK_MONOTONIC) < signal_time));
     alarm(0);
     signal(SIGALRM, SIG_DFL);
 
-    ASSERT_LT(1, count);
+    EXPECT_LT(1, count);
 
-    ASSERT_EQ(1, signals);
+    EXPECT_EQ(1, signals);
 
     android_logger_list_close(logger_list);
 
@@ -293,9 +296,302 @@
     const unsigned long long one_percent_ticks = alarm_time;
     unsigned long long user_ticks = uticks_end - uticks_start;
     unsigned long long system_ticks = sticks_end - sticks_start;
-    ASSERT_GT(one_percent_ticks, user_ticks);
-    ASSERT_GT(one_percent_ticks, system_ticks);
-    ASSERT_GT(one_percent_ticks, user_ticks + system_ticks);
+    EXPECT_GT(one_percent_ticks, user_ticks);
+    EXPECT_GT(one_percent_ticks, system_ticks);
+    EXPECT_GT(one_percent_ticks, user_ticks + system_ticks);
+}
+
+static const char max_payload_tag[] = "TEST_max_payload_XXXX";
+static const char max_payload_buf[LOGGER_ENTRY_MAX_PAYLOAD
+    - sizeof(max_payload_tag) - 1] = "LEONATO\n\
+I learn in this letter that Don Peter of Arragon\n\
+comes this night to Messina\n\
+MESSENGER\n\
+He is very near by this: he was not three leagues off\n\
+when I left him\n\
+LEONATO\n\
+How many gentlemen have you lost in this action?\n\
+MESSENGER\n\
+But few of any sort, and none of name\n\
+LEONATO\n\
+A victory is twice itself when the achiever brings\n\
+home full numbers. I find here that Don Peter hath\n\
+bestowed much honour on a young Florentine called Claudio\n\
+MESSENGER\n\
+Much deserved on his part and equally remembered by\n\
+Don Pedro: he hath borne himself beyond the\n\
+promise of his age, doing, in the figure of a lamb,\n\
+the feats of a lion: he hath indeed better\n\
+bettered expectation than you must expect of me to\n\
+tell you how\n\
+LEONATO\n\
+He hath an uncle here in Messina will be very much\n\
+glad of it.\n\
+MESSENGER\n\
+I have already delivered him letters, and there\n\
+appears much joy in him; even so much that joy could\n\
+not show itself modest enough without a badge of\n\
+bitterness.\n\
+LEONATO\n\
+Did he break out into tears?\n\
+MESSENGER\n\
+In great measure.\n\
+LEONATO\n\
+A kind overflow of kindness: there are no faces\n\
+truer than those that are so washed. How much\n\
+better is it to weep at joy than to joy at weeping!\n\
+BEATRICE\n\
+I pray you, is Signior Mountanto returned from the\n\
+wars or no?\n\
+MESSENGER\n\
+I know none of that name, lady: there was none such\n\
+in the army of any sort.\n\
+LEONATO\n\
+What is he that you ask for, niece?\n\
+HERO\n\
+My cousin means Signior Benedick of Padua.\n\
+MESSENGER\n\
+O, he's returned; and as pleasant as ever he was.\n\
+BEATRICE\n\
+He set up his bills here in Messina and challenged\n\
+Cupid at the flight; and my uncle's fool, reading\n\
+the challenge, subscribed for Cupid, and challenged\n\
+him at the bird-bolt. I pray you, how many hath he\n\
+killed and eaten in these wars? But how many hath\n\
+he killed? for indeed I promised to eat all of his killing.\n\
+LEONATO\n\
+Faith, niece, you tax Signior Benedick too much;\n\
+but he'll be meet with you, I doubt it not.\n\
+MESSENGER\n\
+He hath done good service, lady, in these wars.\n\
+BEATRICE\n\
+You had musty victual, and he hath holp to eat it:\n\
+he is a very valiant trencherman; he hath an\n\
+excellent stomach.\n\
+MESSENGER\n\
+And a good soldier too, lady.\n\
+BEATRICE\n\
+And a good soldier to a lady: but what is he to a lord?\n\
+MESSENGER\n\
+A lord to a lord, a man to a man; stuffed with all\n\
+honourable virtues.\n\
+BEATRICE\n\
+It is so, indeed; he is no less than a stuffed man:\n\
+but for the stuffing,--well, we are all mortal.\n\
+LEONATO\n\
+You must not, sir, mistake my niece. There is a\n\
+kind of merry war betwixt Signior Benedick and her:\n\
+they never meet but there's a skirmish of wit\n\
+between them.\n\
+BEATRICE\n\
+Alas! he gets nothing by that. In our last\n\
+conflict four of his five wits went halting off, and\n\
+now is the whole man governed with one: so that if\n\
+he have wit enough to keep himself warm, let him\n\
+bear it for a difference between himself and his\n\
+horse; for it is all the wealth that he hath left,\n\
+to be known a reasonable creature. Who is his\n\
+companion now? He hath every month a new sworn brother.\n\
+MESSENGER\n\
+Is't possible?\n\
+BEATRICE\n\
+Very easily possible: he wears his faith but as\n\
+the fashion of his hat; it ever changes with the\n\
+next block.\n\
+MESSENGER\n\
+I see, lady, the gentleman is not in your books.\n\
+BEATRICE\n\
+No; an he were, I would burn my study. But, I pray\n\
+you, who is his companion? Is there no young\n\
+squarer now that will make a voyage with him to the devil?\n\
+MESSENGER\n\
+He is most in the company of the right noble Claudio.\n\
+BEATRICE\n\
+O Lord, he will hang upon him like a disease: he\n\
+is sooner caught than the pestilence, and the taker\n\
+runs presently mad. God help the noble Claudio! if\n\
+he have caught the Benedick, it will cost him a\n\
+thousand pound ere a' be cured.\n\
+MESSENGER\n\
+I will hold friends with you, lady.\n\
+BEATRICE\n\
+Do, good friend.\n\
+LEONATO\n\
+You will never run mad, niece.\n\
+BEATRICE\n\
+No, not till a hot January.\n\
+MESSENGER\n\
+Don Pedro is approached.\n\
+Enter DON PEDRO, DON JOHN, CLAUDIO, BENEDICK, and BALTHASAR\n\
+\n\
+DON PEDRO\n\
+Good Signior Leonato, you are come to meet your\n\
+trouble: the fashion of the world is to avoid\n\
+cost, and you encounter it\n\
+LEONATO\n\
+Never came trouble to my house in the likeness";
+
+TEST(liblog, max_payload) {
+    pid_t pid = getpid();
+    char tag[sizeof(max_payload_tag)];
+    memcpy(tag, max_payload_tag, sizeof(tag));
+    snprintf(tag + sizeof(tag) - 5, 5, "%04X", pid & 0xFFFF);
+
+    LOG_FAILURE_RETRY(__android_log_buf_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
+                                              tag, max_payload_buf));
+
+    struct logger_list *logger_list;
+
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+        LOG_ID_SYSTEM, O_RDONLY, 100, 0)));
+
+    bool matches = false;
+    ssize_t max_len = 0;
+
+    for(;;) {
+        log_msg log_msg;
+        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+            break;
+        }
+
+        if ((log_msg.entry.pid != pid) || (log_msg.id() != LOG_ID_SYSTEM)) {
+            continue;
+        }
+
+        char *data = log_msg.msg() + 1;
+
+        if (strcmp(data, tag)) {
+            continue;
+        }
+
+        data += strlen(data) + 1;
+
+        const char *left = data;
+        const char *right = max_payload_buf;
+        while (*left && *right && (*left == *right)) {
+            ++left;
+            ++right;
+        }
+
+        if (max_len <= (left - data)) {
+            max_len = left - data + 1;
+        }
+
+        if (max_len > 512) {
+            matches = true;
+            break;
+        }
+    }
+
+    android_logger_list_close(logger_list);
+
+    EXPECT_EQ(true, matches);
+
+    EXPECT_LE(sizeof(max_payload_buf), static_cast<size_t>(max_len));
+}
+
+TEST(liblog, too_big_payload) {
+    pid_t pid = getpid();
+    static const char big_payload_tag[] = "TEST_big_payload_XXXX";
+    char tag[sizeof(big_payload_tag)];
+    memcpy(tag, big_payload_tag, sizeof(tag));
+    snprintf(tag + sizeof(tag) - 5, 5, "%04X", pid & 0xFFFF);
+
+    std::string longString(3266519, 'x');
+
+    ssize_t ret = LOG_FAILURE_RETRY(__android_log_buf_write(LOG_ID_SYSTEM,
+                                    ANDROID_LOG_INFO, tag, longString.c_str()));
+
+    struct logger_list *logger_list;
+
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+        LOG_ID_SYSTEM, O_RDONLY | O_NDELAY, 100, 0)));
+
+    ssize_t max_len = 0;
+
+    for(;;) {
+        log_msg log_msg;
+        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+            break;
+        }
+
+        if ((log_msg.entry.pid != pid) || (log_msg.id() != LOG_ID_SYSTEM)) {
+            continue;
+        }
+
+        char *data = log_msg.msg() + 1;
+
+        if (strcmp(data, tag)) {
+            continue;
+        }
+
+        data += strlen(data) + 1;
+
+        const char *left = data;
+        const char *right = longString.c_str();
+        while (*left && *right && (*left == *right)) {
+            ++left;
+            ++right;
+        }
+
+        if (max_len <= (left - data)) {
+            max_len = left - data + 1;
+        }
+    }
+
+    android_logger_list_close(logger_list);
+
+    EXPECT_LE(LOGGER_ENTRY_MAX_PAYLOAD - sizeof(big_payload_tag),
+              static_cast<size_t>(max_len));
+
+    EXPECT_EQ(ret, max_len + static_cast<ssize_t>(sizeof(big_payload_tag)));
+}
+
+TEST(liblog, dual_reader) {
+    struct logger_list *logger_list1;
+
+    // >25 messages due to liblog.__android_log_buf_print__concurrentXX above.
+    ASSERT_TRUE(NULL != (logger_list1 = android_logger_list_open(
+        LOG_ID_MAIN, O_RDONLY | O_NDELAY, 25, 0)));
+
+    struct logger_list *logger_list2;
+
+    if (NULL == (logger_list2 = android_logger_list_open(
+            LOG_ID_MAIN, O_RDONLY | O_NDELAY, 15, 0))) {
+        android_logger_list_close(logger_list1);
+        ASSERT_TRUE(NULL != logger_list2);
+    }
+
+    int count1 = 0;
+    bool done1 = false;
+    int count2 = 0;
+    bool done2 = false;
+
+    do {
+        log_msg log_msg;
+
+        if (!done1) {
+            if (android_logger_list_read(logger_list1, &log_msg) <= 0) {
+                done1 = true;
+            } else {
+                ++count1;
+            }
+        }
+
+        if (!done2) {
+            if (android_logger_list_read(logger_list2, &log_msg) <= 0) {
+                done2 = true;
+            } else {
+                ++count2;
+            }
+        }
+    } while ((!done1) || (!done2));
+
+    android_logger_list_close(logger_list1);
+    android_logger_list_close(logger_list2);
+
+    EXPECT_EQ(25, count1);
+    EXPECT_EQ(15, count2);
 }
 
 TEST(liblog, android_logger_get_) {
@@ -308,12 +604,81 @@
             continue;
         }
         struct logger * logger;
-        ASSERT_EQ(0, NULL == (logger = android_logger_open(logger_list, id)));
-        ASSERT_EQ(id, android_logger_get_id(logger));
-        ASSERT_LT(0, android_logger_get_log_size(logger));
-        ASSERT_LT(0, android_logger_get_log_readable_size(logger));
-        ASSERT_LT(0, android_logger_get_log_version(logger));
+        EXPECT_TRUE(NULL != (logger = android_logger_open(logger_list, id)));
+        EXPECT_EQ(id, android_logger_get_id(logger));
+        EXPECT_LT(0, android_logger_get_log_size(logger));
+        EXPECT_LT(0, android_logger_get_log_readable_size(logger));
+        EXPECT_LT(0, android_logger_get_log_version(logger));
     }
 
     android_logger_list_close(logger_list);
 }
+
+static bool checkPriForTag(AndroidLogFormat *p_format, const char *tag, android_LogPriority pri) {
+    return android_log_shouldPrintLine(p_format, tag, pri)
+        && !android_log_shouldPrintLine(p_format, tag, (android_LogPriority)(pri - 1));
+}
+
+TEST(liblog, filterRule) {
+    static const char tag[] = "random";
+
+    AndroidLogFormat *p_format = android_log_format_new();
+
+    android_log_addFilterRule(p_format,"*:i");
+
+    EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_INFO));
+    EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
+    android_log_addFilterRule(p_format, "*");
+    EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_DEBUG));
+    EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
+    android_log_addFilterRule(p_format, "*:v");
+    EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_VERBOSE));
+    EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
+    android_log_addFilterRule(p_format, "*:i");
+    EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_INFO));
+    EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
+
+    android_log_addFilterRule(p_format, tag);
+    EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_VERBOSE));
+    EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
+    android_log_addFilterRule(p_format, "random:v");
+    EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_VERBOSE));
+    EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
+    android_log_addFilterRule(p_format, "random:d");
+    EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_DEBUG));
+    EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
+    android_log_addFilterRule(p_format, "random:w");
+    EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_WARN));
+    EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
+
+    android_log_addFilterRule(p_format, "crap:*");
+    EXPECT_TRUE (checkPriForTag(p_format, "crap", ANDROID_LOG_VERBOSE));
+    EXPECT_TRUE(android_log_shouldPrintLine(p_format, "crap", ANDROID_LOG_VERBOSE) > 0);
+
+    // invalid expression
+    EXPECT_TRUE (android_log_addFilterRule(p_format, "random:z") < 0);
+    EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_WARN));
+    EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
+
+    // Issue #550946
+    EXPECT_TRUE(android_log_addFilterString(p_format, " ") == 0);
+    EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_WARN));
+
+    // note trailing space
+    EXPECT_TRUE(android_log_addFilterString(p_format, "*:s random:d ") == 0);
+    EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_DEBUG));
+
+    EXPECT_TRUE(android_log_addFilterString(p_format, "*:s random:z") < 0);
+
+#if 0 // bitrot, seek update
+    char defaultBuffer[512];
+
+    android_log_formatLogLine(p_format,
+        defaultBuffer, sizeof(defaultBuffer), 0, ANDROID_LOG_ERROR, 123,
+        123, 123, tag, "nofile", strlen("Hello"), "Hello", NULL);
+
+    fprintf(stderr, "%s\n", defaultBuffer);
+#endif
+
+    android_log_format_free(p_format);
+}
diff --git a/libmincrypt/dsa_sig.c b/libmincrypt/dsa_sig.c
index 8df6cf7..101314b 100644
--- a/libmincrypt/dsa_sig.c
+++ b/libmincrypt/dsa_sig.c
@@ -26,6 +26,7 @@
 
 #include <string.h>
 
+#include "mincrypt/dsa_sig.h"
 #include "mincrypt/p256.h"
 
 /**
diff --git a/libmincrypt/p256.c b/libmincrypt/p256.c
index 1608d37..555a07a 100644
--- a/libmincrypt/p256.c
+++ b/libmincrypt/p256.c
@@ -49,8 +49,6 @@
   {{0x27d2604b, 0x3bce3c3e, 0xcc53b0f6, 0x651d06b0,
     0x769886bc, 0xb3ebbd55, 0xaa3a93e7, 0x5ac635d8}};
 
-static const p256_int p256_one = P256_ONE;
-
 void p256_init(p256_int* a) {
   memset(a, 0, sizeof(*a));
 }
diff --git a/libmincrypt/test/ecdsa_test.c b/libmincrypt/test/ecdsa_test.c
index b5a7b3a..24ec013 100644
--- a/libmincrypt/test/ecdsa_test.c
+++ b/libmincrypt/test/ecdsa_test.c
@@ -24,15 +24,21 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <stdio.h>
 #include <ctype.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/cdefs.h>
 
+#include "mincrypt/dsa_sig.h"
 #include "mincrypt/p256.h"
 #include "mincrypt/p256_ecdsa.h"
 #include "mincrypt/sha256.h"
 
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
+
 /**
  * Messages signed using:
  *
@@ -209,7 +215,7 @@
     return result;
 }
 
-int main(int arg, char** argv) {
+int main(int arg __unused, char** argv __unused) {
 
     unsigned char hash_buf[SHA256_DIGEST_SIZE];
 
diff --git a/libmincrypt/test/rsa_test.c b/libmincrypt/test/rsa_test.c
index 17862dc..055138f 100644
--- a/libmincrypt/test/rsa_test.c
+++ b/libmincrypt/test/rsa_test.c
@@ -1,5 +1,4 @@
-/* rsa_test.c
-**
+/*
 ** Copyright 2013, The Android Open Source Project
 **
 ** Redistribution and use in source and binary forms, with or without
@@ -25,14 +24,19 @@
 ** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
-#include <stdio.h>
 #include <ctype.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/cdefs.h>
 
 #include "mincrypt/rsa.h"
 #include "mincrypt/sha.h"
 
+#ifndef __unused
+#define __unused __attribute__((unused))
+#endif
+
 // RSA test data taken from:
 //
 //   ftp://ftp.rsa.com/pub/rsalabs/tmp/pkcs1v15sign-vectors.txt
@@ -791,7 +795,7 @@
 }
 
 
-int main(int arg, char** argv) {
+int main(int arg __unused, char** argv __unused) {
 
     unsigned char hash[SHA_DIGEST_SIZE];
 
diff --git a/libnetutils/Android.mk b/libnetutils/Android.mk
index aba4621..1f61511 100644
--- a/libnetutils/Android.mk
+++ b/libnetutils/Android.mk
@@ -1,7 +1,7 @@
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:= \
+LOCAL_SRC_FILES := \
         dhcpclient.c \
         dhcpmsg.c \
         dhcp_utils.c \
@@ -12,6 +12,8 @@
         libcutils \
         liblog
 
-LOCAL_MODULE:= libnetutils
+LOCAL_MODULE := libnetutils
+
+LOCAL_CFLAGS := -Werror
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/libnetutils/dhcpclient.c b/libnetutils/dhcpclient.c
index 34500e7..b58120e 100644
--- a/libnetutils/dhcpclient.c
+++ b/libnetutils/dhcpclient.c
@@ -282,16 +282,18 @@
     ALOGD("chaddr = {%s}", buf);
 
     for (n = 0; n < 64; n++) {
-        if ((msg->sname[n] < ' ') || (msg->sname[n] > 127)) {
-            if (msg->sname[n] == 0) break;
+        unsigned char x = msg->sname[n];
+        if ((x < ' ') || (x > 127)) {
+            if (x == 0) break;
             msg->sname[n] = '.';
         }
     }
     msg->sname[63] = 0;
 
     for (n = 0; n < 128; n++) {
-        if ((msg->file[n] < ' ') || (msg->file[n] > 127)) {
-            if (msg->file[n] == 0) break;
+        unsigned char x = msg->file[n];
+        if ((x < ' ') || (x > 127)) {
+            if (x == 0) break;
             msg->file[n] = '.';
         }
     }
diff --git a/libnl_2/.gitignore b/libnl_2/.gitignore
deleted file mode 100644
index d4ca744..0000000
--- a/libnl_2/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-include/netlink/version.h.in
-cscope.*
diff --git a/libnl_2/Android.mk b/libnl_2/Android.mk
deleted file mode 100644
index deac9de..0000000
--- a/libnl_2/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-#######################################
-# * Netlink cache not implemented
-# * Library is not thread safe
-#######################################
-
-LOCAL_PATH := $(call my-dir)
-
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-        attr.c \
-        cache.c \
-        genl/genl.c \
-        genl/family.c \
-        handlers.c \
-        msg.c \
-        netlink.c \
-        object.c \
-        socket.c \
-        dbg.c
-
-LOCAL_C_INCLUDES += \
-        external/libnl-headers
-
-# Static Library
-LOCAL_MODULE := libnl_2
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES :=
-LOCAL_WHOLE_STATIC_LIBRARIES:= libnl_2
-LOCAL_SHARED_LIBRARIES:= liblog
-LOCAL_MODULE := libnl_2
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_SHARED_LIBRARY)
diff --git a/libnl_2/README b/libnl_2/README
deleted file mode 100644
index 14db6db..0000000
--- a/libnl_2/README
+++ /dev/null
@@ -1,88 +0,0 @@
-Netlink Protocol Library
-
-This library is a clean room re-implementation of libnl 2.0 and
-re-licensed under Apache 2.0. It was developed primarily to support
-wpa_supplicant. However, with additional development can be extended
-to support other netlink applications.
-
-Netlink Protocol Format (RFC3549)
-
-+-----------------+-+-------------------+-+
-|Netlink Message  |P| Generic Netlink   |P|
-|    Header       |A|  Message Header   |A|
-|(struct nlmsghdr)|D|(struct genlmsghdr)|D|
-+-----------------+-+-------------------+-+-------------+
-|len:4|type:2|flags:2|seq:4 pid:4|cmd:1|ver:1|reserved:2|
-+--------------------------------+----------------------+
-+-----------------+-+-----------------+-+-----------------+-+-----------------+-+---+
-|Netlink Attribute|P|Netlink Attribute|P|Netlink Attribute|P|Netlink Attribute|P|...|
-|    #0 Header    |A|   #0 Payload    |A|   #1 Header     |A|   #1 Payload    |A|   |
-| (struct nlattr) |D|     (void)      |D| (struct nlattr) |D|     (void)      |D|   |
-+-----------------+-+-----------------+-+-----------------+-+-----------------+-+---+
-|len:2(==4+payload)|type:2|payload|pad|
-+-------------------------+-------+---+
-
-NETLINK OVERVIEW
-
-* Each netlink message consists of a bitstream with a netlink header.
-* After this header a second header *can* be used specific to the netlink
-  family in use. This library was tested using the generic netlink
-  protocol defined by struct genlmsghdr to support nl80211.
-* After the header(s) netlink attributes can be appended to the message
-  which hold can hold basic types such as unsigned integers and strings.
-* Attributes can also be nested. This is accomplished by calling "nla_nest_start"
-  which creates an empty attribute with nest attributes as its payload. Then to
-  close the nest, "nla_nest_end" is called.
-* All data structures in this implementation are byte-aligned (Currently 4 bytes).
-* Acknowledgements (ACKs) are sent as NLMSG_ERROR netlink message types (0x2) and
-  have an error value of 0.
-
-KNOWN ISSUES
-
-  GENERAL
-  * Not tested for thread safety
-
-  Android.mk
-  * No dynamic library because of netlink cache not implemented and
-    not tested for thread safety
-
-  attr.c
-  * nla_parse - does not use nla_policy argument
-
-  cache.c
-  * netlink cache not implemented and only supports one netlink family id
-    which is stored in the nl_cache pointer instead of an actual cache
-
-  netlink.c
-  * nl_recvmsgs - does not support nl_cb_overwrite_recv()
-  * nl_recv - sets/unsets asynchronous socket flag
-
-SOURCE FILES
-
-* Android.mk - Android makefile
-* README - This file
-* attr.c - Netlink attributes
-* cache.c - Netlink cache
-* genl/family.c - Generic netlink family id
-* genl/genl.c - Generic netlink
-* handlers.c - Netlink callbacks
-* msg.c - Netlink messages construction
-* netlink.c - Netlink socket communication
-* object.c - libnl object wrapper
-* socket.c - Netlink kernel socket utils
-
-IMPORTANT HEADER FILES - NOTE: These are based on the the origin GPL libnl headers
-
-* netlink-types.h - Contains many important structs for libnl
-  to represent netlink objects
-* netlink/netlink-kernel.h - Netlink kernel headers and field constants.
-* netlink/msg.h - macros for iterating over netlink messages
-* netlink/attr.h - netlink attribute constants, iteration macros and setters
-
-REFERENCES
-
-* nl80211.h
-* netlink_types.h
-* $LINUX_KERNEL/net/wireless/nl80211.c
-* http://www.infradead.org/~tgr/libnl/doc-3.0/index.html
-* http://www.netfilter.org/projects/libmnl/doxygen/index.html
diff --git a/libnl_2/attr.c b/libnl_2/attr.c
deleted file mode 100644
index 2ef7590..0000000
--- a/libnl_2/attr.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *	http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include <errno.h>
-#include "netlink/netlink.h"
-#include "netlink/msg.h"
-#include "netlink/attr.h"
-#include "netlink-types.h"
-
-/* Return payload of string attribute. */
-char *nla_get_string(struct nlattr *nla)
-{
-	return (char *) nla_data(nla);
-}
-
-/* Return payload of 16 bit integer attribute. */
-uint16_t nla_get_u16(struct nlattr *nla)
-{
-	return *((uint16_t *) nla_data(nla));
-}
-
-/* Return payload of 32 bit integer attribute. */
-uint32_t nla_get_u32(struct nlattr *nla)
-{
-	return *((uint32_t *) nla_data(nla));
-}
-
-/* Return value of 8 bit integer attribute. */
-uint8_t nla_get_u8(struct nlattr *nla)
-{
-	return *((uint8_t *) nla_data(nla));
-}
-
-/* Return payload of uint64_t attribute. */
-uint64_t nla_get_u64(struct nlattr *nla)
-{
-	uint64_t tmp;
-	nla_memcpy(&tmp, nla, sizeof(tmp));
-	return tmp;
-}
-
-/* Head of payload */
-void *nla_data(const struct nlattr *nla)
-{
-	return (void *) ((char *) nla + NLA_HDRLEN);
-}
-
-/* Return length of the payload . */
-int nla_len(const struct nlattr *nla)
-{
-	return nla->nla_len - NLA_HDRLEN;
-}
-
-int nla_padlen(int payload)
-{
-	return NLA_ALIGN(payload) - payload;
-}
-
-/* Start a new level of nested attributes. */
-struct nlattr *nla_nest_start(struct nl_msg *msg, int attrtype)
-{
-	struct nlattr *start = (struct nlattr *)nlmsg_tail(msg->nm_nlh);
-	int rc;
-
-	rc = nla_put(msg, attrtype, 0, NULL);
-	if (rc < 0)
-		return NULL;
-
-	return start;
-}
-
-/* Finalize nesting of attributes. */
-int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
-{
-	/* Set attribute size */
-	start->nla_len = (unsigned char *)nlmsg_tail(nlmsg_hdr(msg)) -
-				(unsigned char *)start;
-	return 0;
-}
-
-/* Return next attribute in a stream of attributes. */
-struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
-{
-	struct nlattr *next_nla = NULL;
-	if (nla->nla_len >= sizeof(struct nlattr) &&
-	   nla->nla_len <= *remaining){
-		next_nla = (struct nlattr *) \
-			((char *) nla + NLA_ALIGN(nla->nla_len));
-		*remaining = *remaining - NLA_ALIGN(nla->nla_len);
-	}
-
-	return next_nla;
-
-}
-
-/* Check if the attribute header and payload can be accessed safely. */
-int nla_ok(const struct nlattr *nla, int remaining)
-{
-	return remaining > 0 &&
-		nla->nla_len >= sizeof(struct nlattr) &&
-		sizeof(struct nlattr) <= (unsigned int) remaining &&
-		nla->nla_len <= remaining;
-}
-
-/* Create attribute index based on a stream of attributes. */
-/* NOTE: Policy not used ! */
-int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head,
-	int len, struct nla_policy *policy)
-{
-	struct nlattr *pos;
-	int rem;
-
-	/* First clear table */
-	memset(tb, 0, (maxtype + 1) * sizeof(struct nlattr *));
-
-	nla_for_each_attr(pos, head, len, rem) {
-		int type = nla_type(pos);
-
-		if ((type <= maxtype) && (type != 0))
-			tb[type] = pos;
-	}
-
-	return 0;
-}
-
-
-/* Create attribute index based on nested attribute. */
-int nla_parse_nested(struct nlattr *tb[], int maxtype,
-		struct nlattr *nla, struct nla_policy *policy)
-{
-	return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy);
-}
-
-
-/* Add a unspecific attribute to netlink message. */
-int nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data)
-{
-	struct nlattr *nla;
-
-	/* Reserve space and init nla header */
-	nla = nla_reserve(msg, attrtype, datalen);
-	if (nla) {
-		memcpy(nla_data(nla), data, datalen);
-		return 0;
-	}
-
-	return -EINVAL;
-}
-
-/* Add 8 bit integer attribute to netlink message. */
-int nla_put_u8(struct nl_msg *msg, int attrtype, uint8_t value)
-{
-	return nla_put(msg, attrtype, sizeof(uint8_t), &value);
-}
-
-/* Add 16 bit integer attribute to netlink message. */
-int nla_put_u16(struct nl_msg *msg, int attrtype, uint16_t value)
-{
-	return nla_put(msg, attrtype, sizeof(uint16_t), &value);
-}
-
-/* Add 32 bit integer attribute to netlink message. */
-int nla_put_u32(struct nl_msg *msg, int attrtype, uint32_t value)
-{
-	return nla_put(msg, attrtype, sizeof(uint32_t), &value);
-}
-
-/* Add 64 bit integer attribute to netlink message. */
-int nla_put_u64(struct nl_msg *msg, int attrtype, uint64_t value)
-{
-	return nla_put(msg, attrtype, sizeof(uint64_t), &value);
-}
-
-/* Add nested attributes to netlink message. */
-/* Takes the attributes found in the nested message and appends them
- * to the message msg nested in a container of the type attrtype. The
- * nested message may not have a family specific header */
-int nla_put_nested(struct nl_msg *msg, int attrtype, struct nl_msg *nested)
-{
-	int rc;
-
-	rc = nla_put(msg, attrtype, nlmsg_attrlen(nlmsg_hdr(nested), 0),
-			nlmsg_attrdata(nlmsg_hdr(nested), 0));
-	return rc;
-
-}
-
-/* Return type of the attribute. */
-int nla_type(const struct nlattr *nla)
-{
-	return (int)nla->nla_type & NLA_TYPE_MASK;
-}
-
-/* Reserves room for an attribute in specified netlink message and fills
- * in the attribute header (type,length). Return NULL if insufficient space */
-struct nlattr *nla_reserve(struct nl_msg *msg, int attrtype, int data_len)
-{
-
-	struct nlattr *nla;
-	const unsigned int NEW_SIZE = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) +
-					NLA_ALIGN(NLA_HDRLEN + data_len);
-
-	/* Check enough space for attribute */
-	if (NEW_SIZE > msg->nm_size)
-		return NULL;
-
-	nla = (struct nlattr *)nlmsg_tail(msg->nm_nlh);
-	nla->nla_type = attrtype;
-	nla->nla_len = NLA_HDRLEN + data_len;
-	memset((unsigned char *)nla + nla->nla_len, 0, nla_padlen(data_len));
-	msg->nm_nlh->nlmsg_len = NEW_SIZE;
-	return nla;
-}
-
-/* Copy attribute payload to another memory area. */
-int nla_memcpy(void *dest, struct nlattr *src, int count)
-{
-	if (!src || !dest)
-		return 0;
-	if (count > nla_len(src))
-		count = nla_len(src);
-	memcpy(dest, nla_data(src), count);
-	return count;
-}
diff --git a/libnl_2/dbg.c b/libnl_2/dbg.c
deleted file mode 100644
index 9764de6..0000000
--- a/libnl_2/dbg.c
+++ /dev/null
@@ -1,12 +0,0 @@
-#include "netlink/netlink.h"
-#include <android/log.h>
-
-void libnl_printf(int level, char *format, ...)
-{
-	va_list ap;
-
-	level = ANDROID_LOG_ERROR;
-	va_start(ap, format);
-	__android_log_vprint(level, "libnl_2", format, ap);
-	va_end(ap);
-}
diff --git a/libnl_2/genl/family.c b/libnl_2/genl/family.c
deleted file mode 100644
index 1beee6e..0000000
--- a/libnl_2/genl/family.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *	http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include "netlink-types.h"
-
-static struct genl_family *genl_family_find_byname(const char *name)
-{
-	return NULL;
-}
-
-/* Release reference and none outstanding  */
-void genl_family_put(struct genl_family *family)
-{
-	family->ce_refcnt--;
-	if (family->ce_refcnt <= 0)
-		free(family);
-}
-
-unsigned int genl_family_get_id(struct genl_family *family)
-{
-	const int NO_FAMILY_ID = 0;
-
-	if (!family)
-		return NO_FAMILY_ID;
-	else
-		return family->gf_id;
-
-}
-
diff --git a/libnl_2/genl/genl.c b/libnl_2/genl/genl.c
deleted file mode 100644
index 1a39c6a..0000000
--- a/libnl_2/genl/genl.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *	http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include <errno.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <linux/netlink.h>
-#include <netlink/genl/ctrl.h>
-#include <netlink/genl/family.h>
-#include "netlink-types.h"
-
-/* Get head of attribute data. */
-struct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen)
-{
-	return (struct nlattr *) \
-		((char *) gnlh + GENL_HDRLEN + NLMSG_ALIGN(hdrlen));
-
-}
-
-/* Get length of attribute data. */
-int genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen)
-{
-	struct nlattr *nla;
-	struct nlmsghdr *nlh;
-
-	nla = genlmsg_attrdata(gnlh, hdrlen);
-	nlh = (struct nlmsghdr *) ((char *) gnlh - NLMSG_HDRLEN);
-	return (char *) nlmsg_tail(nlh) - (char *) nla;
-}
-
-/* Add generic netlink header to netlink message. */
-void *genlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq, int family,
-		int hdrlen, int flags, uint8_t cmd, uint8_t version)
-{
-	int new_size;
-	struct nlmsghdr *nlh;
-	struct timeval tv;
-	struct genlmsghdr *gmh;
-
-	/* Make sure nl_msg has enough space */
-	new_size = NLMSG_HDRLEN + GENL_HDRLEN + hdrlen;
-	if ((sizeof(struct nl_msg) + new_size) > msg->nm_size)
-		goto fail;
-
-	/* Fill in netlink header */
-	nlh = msg->nm_nlh;
-	nlh->nlmsg_len = new_size;
-	nlh->nlmsg_type = family;
-	nlh->nlmsg_pid = getpid();
-	nlh->nlmsg_flags = flags | NLM_F_REQUEST | NLM_F_ACK;
-
-	/* Get current time for sequence number */
-	if (gettimeofday(&tv, NULL))
-		nlh->nlmsg_seq = 1;
-	else
-		nlh->nlmsg_seq = (int) tv.tv_sec;
-
-	/* Setup genlmsghdr in new message */
-	gmh = (struct genlmsghdr *) ((char *)nlh + NLMSG_HDRLEN);
-	gmh->cmd = (__u8) cmd;
-	gmh->version = version;
-
-	return gmh;
-fail:
-	return NULL;
-
-}
-
-/* Socket has already been alloced to connect it to kernel? */
-int genl_connect(struct nl_sock *sk)
-{
-	return nl_connect(sk, NETLINK_GENERIC);
-
-}
-
-int genl_ctrl_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
-{
-	int rc = -1;
-	int nl80211_genl_id = -1;
-	char sendbuf[sizeof(struct nlmsghdr)+sizeof(struct genlmsghdr)];
-	struct nlmsghdr nlmhdr;
-	struct genlmsghdr gmhhdr;
-	struct iovec sendmsg_iov;
-	struct msghdr msg;
-	int num_char;
-	const int RECV_BUF_SIZE = getpagesize();
-	char *recvbuf;
-	struct iovec recvmsg_iov;
-	int nl80211_flag = 0, nlm_f_multi = 0, nlmsg_done = 0;
-	struct nlmsghdr *nlh;
-
-	/* REQUEST GENERIC NETLINK FAMILY ID */
-	/* Message buffer */
-	nlmhdr.nlmsg_len = sizeof(sendbuf);
-	nlmhdr.nlmsg_type = NETLINK_GENERIC;
-	nlmhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
-	nlmhdr.nlmsg_seq = sock->s_seq_next;
-	nlmhdr.nlmsg_pid = sock->s_local.nl_pid;
-
-	/* Generic netlink header */
-	memset(&gmhhdr, 0, sizeof(gmhhdr));
-	gmhhdr.cmd = CTRL_CMD_GETFAMILY;
-	gmhhdr.version = CTRL_ATTR_FAMILY_ID;
-
-	/* Combine netlink and generic netlink headers */
-	memcpy(&sendbuf[0], &nlmhdr, sizeof(nlmhdr));
-	memcpy(&sendbuf[0]+sizeof(nlmhdr), &gmhhdr, sizeof(gmhhdr));
-
-	/* Create IO vector with Netlink message */
-	sendmsg_iov.iov_base = &sendbuf;
-	sendmsg_iov.iov_len = sizeof(sendbuf);
-
-	/* Socket message */
-	msg.msg_name = (void *) &sock->s_peer;
-	msg.msg_namelen = sizeof(sock->s_peer);
-	msg.msg_iov = &sendmsg_iov;
-	msg.msg_iovlen = 1; /* Only sending one iov */
-	msg.msg_control = NULL;
-	msg.msg_controllen = 0;
-	msg.msg_flags = 0;
-
-	/* Send message and verify sent */
-	num_char = sendmsg(sock->s_fd, &msg, 0);
-	if (num_char == -1)
-		return -errno;
-
-	/* RECEIVE GENL CMD RESPONSE */
-
-	/* Create receive iov buffer */
-	recvbuf = (char *) malloc(RECV_BUF_SIZE);
-
-	/* Attach to iov */
-	recvmsg_iov.iov_base = recvbuf;
-	recvmsg_iov.iov_len = RECV_BUF_SIZE;
-
-	msg.msg_iov = &recvmsg_iov;
-	msg.msg_iovlen = 1;
-
-	/***************************************************************/
-	/* Receive message. If multipart message, keep receiving until */
-	/* message type is NLMSG_DONE				       */
-	/***************************************************************/
-
-	do {
-
-		int recvmsg_len, nlmsg_rem;
-
-		/* Receive message */
-		memset(recvbuf, 0, RECV_BUF_SIZE);
-		recvmsg_len = recvmsg(sock->s_fd, &msg, 0);
-
-		/* Make sure receive successful */
-		if (recvmsg_len < 0) {
-			rc = -errno;
-			goto error_recvbuf;
-		}
-
-		/* Parse nlmsghdr */
-		nlmsg_for_each_msg(nlh, (struct nlmsghdr *) recvbuf, \
-				recvmsg_len, nlmsg_rem) {
-			struct nlattr *nla;
-			int nla_rem;
-
-			/* Check type */
-			switch (nlh->nlmsg_type) {
-			case NLMSG_DONE:
-				goto return_genl_id;
-				break;
-			case NLMSG_ERROR:
-
-				/* Should check nlmsgerr struct received */
-				fprintf(stderr, "Receive message error\n");
-				goto error_recvbuf;
-			case NLMSG_OVERRUN:
-				fprintf(stderr, "Receive data partly lost\n");
-				goto error_recvbuf;
-			case NLMSG_MIN_TYPE:
-			case NLMSG_NOOP:
-				break;
-			default:
-				break;
-			}
-
-
-
-			/* Check flags */
-			if (nlh->nlmsg_flags & NLM_F_MULTI)
-				nlm_f_multi = 1;
-			else
-				nlm_f_multi = 0;
-
-			if (nlh->nlmsg_type & NLMSG_DONE)
-				nlmsg_done = 1;
-			else
-				nlmsg_done = 0;
-
-			/* Iteratve over attributes */
-			nla_for_each_attr(nla,
-					nlmsg_attrdata(nlh, GENL_HDRLEN),
-					nlmsg_attrlen(nlh, GENL_HDRLEN),
-					nla_rem){
-
-				/* If this family is nl80211 */
-				if (nla->nla_type == CTRL_ATTR_FAMILY_NAME &&
-					!strcmp((char *)nla_data(nla),
-						"nl80211"))
-					nl80211_flag = 1;
-
-				/* Save the family id */
-				else if (nl80211_flag &&
-					nla->nla_type == CTRL_ATTR_FAMILY_ID) {
-					nl80211_genl_id =
-						*((int *)nla_data(nla));
-					nl80211_flag = 0;
-				}
-
-			}
-
-		}
-
-	} while (nlm_f_multi && !nlmsg_done);
-
-return_genl_id:
-	/* Return family id as cache pointer */
-	*result = (struct nl_cache *) nl80211_genl_id;
-	rc = 0;
-error_recvbuf:
-	free(recvbuf);
-error:
-	return rc;
-}
-
-/* Checks the netlink cache to find family reference by name string */
-/* NOTE: Caller needs to call genl_family_put() when done with *
- * returned object */
-struct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache, \
-					const char *name)
-{
-	struct genl_family *gf = (struct genl_family *) \
-		malloc(sizeof(struct genl_family));
-	if (!gf)
-		goto fail;
-	memset(gf, 0, sizeof(*gf));
-
-	/* Add ref */
-	gf->ce_refcnt++;
-
-	/* Overriding cache pointer as family id for now */
-	gf->gf_id = (uint16_t) ((uint32_t) cache);
-	strncpy(gf->gf_name, name, GENL_NAMSIZ);
-
-	return gf;
-fail:
-	return NULL;
-
-}
-
-int genl_ctrl_resolve(struct nl_sock *sk, const char *name)
-{
-	struct nl_cache *cache = NULL;
-	struct genl_family *gf = NULL;
-	int id = -1;
-
-	/* Hack to support wpa_supplicant */
-	if (strcmp(name, "nlctrl") == 0)
-		return NETLINK_GENERIC;
-
-	if (strcmp(name, "nl80211") != 0) {
-		fprintf(stderr, "%s is not supported\n", name);
-		return id;
-	}
-
-	if (!genl_ctrl_alloc_cache(sk, &cache)) {
-		gf = genl_ctrl_search_by_name(cache, name);
-		if (gf)
-			id = genl_family_get_id(gf);
-	}
-
-	if (gf)
-		genl_family_put(gf);
-	if (cache)
-		nl_cache_free(cache);
-
-	return id;
-}
diff --git a/libnl_2/handlers.c b/libnl_2/handlers.c
deleted file mode 100644
index 48dcab4..0000000
--- a/libnl_2/handlers.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *	http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include <malloc.h>
-#include "netlink-types.h"
-#include "netlink/handlers.h"
-
-/* Allocate a new callback handle. */
-struct nl_cb *nl_cb_alloc(enum nl_cb_kind kind)
-{
-	struct nl_cb *cb;
-
-	cb = (struct nl_cb *) malloc(sizeof(struct nl_cb));
-	if (cb == NULL)
-		goto fail;
-	memset(cb, 0, sizeof(*cb));
-
-	return nl_cb_get(cb);
-fail:
-	return NULL;
-}
-
-/* Clone an existing callback handle */
-struct nl_cb *nl_cb_clone(struct nl_cb *orig)
-{
-	struct nl_cb *new_cb;
-
-	new_cb = nl_cb_alloc(NL_CB_DEFAULT);
-	if (new_cb == NULL)
-		goto fail;
-
-	/* Copy original and set refcount to 1 */
-	memcpy(new_cb, orig, sizeof(*orig));
-	new_cb->cb_refcnt = 1;
-
-	return new_cb;
-fail:
-	return NULL;
-}
-
-/* Set up a callback. */
-int nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind, \
-	nl_recvmsg_msg_cb_t func, void *arg)
-{
-	cb->cb_set[type] = func;
-	cb->cb_args[type] = arg;
-	return 0;
-}
-
-
-
-/* Set up an error callback. */
-int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind, \
-	nl_recvmsg_err_cb_t func, void *arg)
-{
-	cb->cb_err = func;
-	cb->cb_err_arg = arg;
-	return 0;
-
-}
-
-struct nl_cb *nl_cb_get(struct nl_cb *cb)
-{
-	cb->cb_refcnt++;
-	return cb;
-}
-
-void nl_cb_put(struct nl_cb *cb)
-{
-	if (!cb)
-		return;
-	cb->cb_refcnt--;
-	if (cb->cb_refcnt <= 0)
-		free(cb);
-}
diff --git a/libnl_2/msg.c b/libnl_2/msg.c
deleted file mode 100644
index 1303e8a..0000000
--- a/libnl_2/msg.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *	http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include <malloc.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <linux/netlink.h>
-#include "netlink-types.h"
-
-/* Allocate a new netlink message with the default maximum payload size. */
-struct nl_msg *nlmsg_alloc(void)
-{
-	/* Whole page will store nl_msg + nlmsghdr + genlmsghdr + payload */
-	const int page_sz = getpagesize();
-	struct nl_msg *nm;
-	struct nlmsghdr *nlh;
-
-	/* Netlink message */
-	nm = (struct nl_msg *) malloc(page_sz);
-	if (!nm)
-		goto fail;
-
-	/* Netlink message header pointer */
-	nlh = (struct nlmsghdr *) ((char *) nm + sizeof(struct nl_msg));
-
-	/* Initialize */
-	memset(nm, 0, page_sz);
-	nm->nm_size = page_sz;
-
-	nm->nm_src.nl_family = AF_NETLINK;
-	nm->nm_src.nl_pid = getpid();
-
-	nm->nm_dst.nl_family = AF_NETLINK;
-	nm->nm_dst.nl_pid = 0; /* Kernel */
-
-	/* Initialize and add to netlink message */
-	nlh->nlmsg_len = NLMSG_HDRLEN;
-	nm->nm_nlh = nlh;
-
-	/* Add to reference count and return nl_msg */
-	nlmsg_get(nm);
-	return nm;
-fail:
-	return NULL;
-}
-
-/* Return pointer to message payload. */
-void *nlmsg_data(const struct nlmsghdr *nlh)
-{
-	return (char *) nlh + NLMSG_HDRLEN;
-}
-
-/* Add reference count to nl_msg */
-void nlmsg_get(struct nl_msg *nm)
-{
-	nm->nm_refcnt++;
-}
-
-/* Release a reference from an netlink message. */
-void nlmsg_free(struct nl_msg *nm)
-{
-	if (nm) {
-		nm->nm_refcnt--;
-		if (nm->nm_refcnt <= 0)
-			free(nm);
-	}
-
-}
-
-/* Return actual netlink message. */
-struct nlmsghdr *nlmsg_hdr(struct nl_msg *n)
-{
-	return n->nm_nlh;
-}
-
-/* Return head of attributes data / payload section */
-struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, int hdrlen)
-{
-	unsigned char *data = nlmsg_data(nlh);
-	return (struct nlattr *)(data + NLMSG_ALIGN(hdrlen));
-}
-
-/* Returns pointer to end of netlink message */
-void *nlmsg_tail(const struct nlmsghdr *nlh)
-{
-	return (void *)((char *)nlh + NLMSG_ALIGN(nlh->nlmsg_len));
-}
-
-/* Next netlink message in message stream */
-struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining)
-{
-	struct nlmsghdr *next_nlh = NULL;
-	int len = nlmsg_len(nlh);
-
-	len = NLMSG_ALIGN(len);
-	if (*remaining > 0 &&
-	    len <= *remaining &&
-	    len >= (int) sizeof(struct nlmsghdr)) {
-		next_nlh = (struct nlmsghdr *)((char *)nlh + len);
-		*remaining -= len;
-	}
-
-	return next_nlh;
-}
-
-int nlmsg_datalen(const struct nlmsghdr *nlh)
-{
-	return nlh->nlmsg_len - NLMSG_HDRLEN;
-}
-
-/* Length of attributes data */
-int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen)
-{
-	return nlmsg_datalen(nlh) - NLMSG_ALIGN(hdrlen);
-}
-
-/* Length of netlink message */
-int nlmsg_len(const struct nlmsghdr *nlh)
-{
-	return nlh->nlmsg_len;
-}
-
-/* Check if the netlink message fits into the remaining bytes */
-int nlmsg_ok(const struct nlmsghdr *nlh, int rem)
-{
-	return rem >= (int)sizeof(struct nlmsghdr) &&
-		rem >= nlmsg_len(nlh) &&
-		nlmsg_len(nlh) >= (int) sizeof(struct nlmsghdr) &&
-		nlmsg_len(nlh) <= (rem);
-}
-
-int nlmsg_padlen(int payload)
-{
-	return NLMSG_ALIGN(payload) - payload;
-}
diff --git a/libnl_2/netlink.c b/libnl_2/netlink.c
deleted file mode 100644
index ee3d600..0000000
--- a/libnl_2/netlink.c
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *	http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include "netlink-types.h"
-
-#define NL_BUFFER_SZ (32768U)
-
-/* Checks message for completeness and sends it out */
-int nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
-{
-	struct nlmsghdr *nlh = msg->nm_nlh;
-	struct timeval tv;
-
-	if (!nlh) {
-		int errsv = errno;
-		fprintf(stderr, "Netlink message header is NULL!\n");
-		return -errsv;
-	}
-
-	/* Complete the nl_msg header */
-	if (gettimeofday(&tv, NULL))
-		nlh->nlmsg_seq = 1;
-	else
-		nlh->nlmsg_seq = (int) tv.tv_sec;
-	nlh->nlmsg_pid = sk->s_local.nl_pid;
-	nlh->nlmsg_flags |= NLM_F_REQUEST | NLM_F_ACK;
-
-	return nl_send(sk, msg);
-}
-
-/* Receives a netlink message, allocates a buffer in *buf and stores
- * the message content. The peer's netlink address is stored in
- * *nla. The caller is responsible for freeing the buffer allocated in
- * *buf if a positive value is returned. Interrupted system calls are
- * handled by repeating the read. The input buffer size is determined
- * by peeking before the actual read is done */
-int nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla, \
-	unsigned char **buf, struct ucred **creds)
-{
-	int rc = -1;
-	int sk_flags;
-	int RECV_BUF_SIZE = getpagesize();
-	int errsv;
-	struct iovec recvmsg_iov;
-	struct msghdr msg;
-
-	/* Allocate buffer */
-	*buf = (unsigned char *) malloc(RECV_BUF_SIZE);
-	if (!(*buf)) {
-		rc = -ENOMEM;
-		goto fail;
-	}
-
-	/* Prepare to receive message */
-	recvmsg_iov.iov_base = *buf;
-	recvmsg_iov.iov_len = RECV_BUF_SIZE;
-
-	msg.msg_name = (void *) &sk->s_peer;
-	msg.msg_namelen = sizeof(sk->s_peer);
-	msg.msg_iov = &recvmsg_iov;
-	msg.msg_iovlen = 1;
-	msg.msg_control = NULL;
-	msg.msg_controllen = 0;
-	msg.msg_flags = 0;
-
-	/* Make non blocking and then restore previous setting */
-	sk_flags = fcntl(sk->s_fd, F_GETFL, 0);
-	fcntl(sk->s_fd, F_SETFL, O_NONBLOCK);
-	rc = recvmsg(sk->s_fd, &msg, 0);
-	errsv = errno;
-	fcntl(sk->s_fd, F_SETFL, sk_flags);
-
-	if (rc < 0) {
-		rc = -errsv;
-		free(*buf);
-		*buf = NULL;
-	}
-
-fail:
-	return rc;
-}
-
-/* Receive a set of messages from a netlink socket */
-/* NOTE: Does not currently support callback replacements!!! */
-int nl_recvmsgs(struct nl_sock *sk, struct nl_cb *cb)
-{
-	struct sockaddr_nl nla;
-	struct ucred *creds;
-
-	int rc, cb_rc = NL_OK, done = 0;
-
-	do {
-		unsigned char *buf;
-		int i, rem, flags;
-		struct nlmsghdr *nlh;
-		struct nlmsgerr *nlme;
-		struct nl_msg *msg;
-
-		done = 0;
-		rc = nl_recv(sk, &nla, &buf, &creds);
-		if (rc < 0)
-			break;
-
-		nlmsg_for_each_msg(nlh, (struct nlmsghdr *) buf, rc, rem) {
-
-			if (rc <= 0 || cb_rc == NL_STOP)
-				break;
-
-			/* Check for callbacks */
-
-			msg = (struct nl_msg *) malloc(sizeof(struct nl_msg));
-			memset(msg, 0, sizeof(*msg));
-			msg->nm_nlh = nlh;
-
-			/* Check netlink message type */
-
-			switch (msg->nm_nlh->nlmsg_type) {
-			case NLMSG_ERROR:	  /* Used for ACK too */
-				/* Certainly we should be doing some
-				 * checking here to make sure this
-				 * message is intended for us */
-				nlme = nlmsg_data(msg->nm_nlh);
-				if (nlme->error == 0)
-					msg->nm_nlh->nlmsg_flags |= NLM_F_ACK;
-
-				rc = nlme->error;
-				cb_rc = cb->cb_err(&nla, nlme, cb->cb_err_arg);
-				nlme = NULL;
-				break;
-
-			case NLMSG_DONE:
-				done = 1;
-
-			case NLMSG_OVERRUN:
-			case NLMSG_NOOP:
-			default:
-				break;
-			};
-
-			for (i = 0; i <= NL_CB_TYPE_MAX; i++) {
-
-				if (cb->cb_set[i]) {
-					switch (i) {
-					case NL_CB_VALID:
-						if (rc > 0)
-							cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
-						break;
-
-					case NL_CB_FINISH:
-						if ((msg->nm_nlh->nlmsg_flags & NLM_F_MULTI) &&
-							(msg->nm_nlh->nlmsg_type & NLMSG_DONE))
-							cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
-
-						break;
-
-					case NL_CB_ACK:
-						if (msg->nm_nlh->nlmsg_flags & NLM_F_ACK)
-							cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
-
-						break;
-					default:
-						break;
-					}
-				}
-			}
-
-			free(msg);
-			if (done)
-				break;
-		}
-		free(buf);
-		buf = NULL;
-
-		if (done)
-			break;
-	} while (rc > 0 && cb_rc != NL_STOP);
-
-success:
-fail:
-	return rc;
-}
-
-/* Send raw data over netlink socket */
-int nl_send(struct nl_sock *sk, struct nl_msg *msg)
-{
-	struct nlmsghdr *nlh = nlmsg_hdr(msg);
-	struct iovec msg_iov;
-
-	/* Create IO vector with Netlink message */
-	msg_iov.iov_base = nlh;
-	msg_iov.iov_len = nlh->nlmsg_len;
-
-	return nl_send_iovec(sk, msg, &msg_iov, 1);
-}
-
-/* Send netlink message */
-int nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg,
-		   struct iovec *iov, unsigned iovlen)
-{
-	int rc;
-
-	/* Socket message */
-	struct msghdr mh = {
-		.msg_name = (void *) &sk->s_peer,
-		.msg_namelen = sizeof(sk->s_peer),
-		.msg_iov = iov,
-		.msg_iovlen = iovlen,
-		.msg_control = NULL,
-		.msg_controllen = 0,
-		.msg_flags = 0
-	};
-
-	/* Send message and verify sent */
-	rc = nl_sendmsg(sk, (struct nl_msg *) &mh, 0);
-	if (rc < 0)
-		fprintf(stderr, "Error sending netlink message: %d\n", errno);
-	return rc;
-
-}
-
-/* Send netlink message with control over sendmsg() message header */
-int nl_sendmsg(struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr)
-{
-	return sendmsg(sk->s_fd, (struct msghdr *) msg, (int) hdr);
-}
-
-/* Create and connect netlink socket */
-int nl_connect(struct nl_sock *sk, int protocol)
-{
-	struct sockaddr addr;
-	socklen_t addrlen;
-	int rc;
-
-	/* Create RX socket */
-	sk->s_fd = socket(PF_NETLINK, SOCK_RAW, protocol);
-	if (sk->s_fd < 0)
-		return -errno;
-
-	/* Set size of RX and TX buffers */
-	if (nl_socket_set_buffer_size(sk, NL_BUFFER_SZ, NL_BUFFER_SZ) < 0)
-		return -errno;
-
-	/* Bind RX socket */
-	rc = bind(sk->s_fd, (struct sockaddr *)&sk->s_local, \
-		sizeof(sk->s_local));
-	if (rc < 0)
-		return -errno;
-	addrlen = sizeof(addr);
-	getsockname(sk->s_fd, &addr, &addrlen);
-
-	return 0;
-
-}
diff --git a/libnl_2/object.c b/libnl_2/object.c
deleted file mode 100644
index c53accf..0000000
--- a/libnl_2/object.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *	http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include "netlink-types.h"
-
-void nl_object_put(struct nl_object *obj)
-{
-	obj->ce_refcnt--;
-	if (!obj->ce_refcnt)
-		nl_object_free(obj);
-}
-
-void nl_object_free(struct nl_object *obj)
-{
-	nl_cache_remove(obj);
-}
-
-
diff --git a/libnl_2/socket.c b/libnl_2/socket.c
deleted file mode 100644
index e94eb9e..0000000
--- a/libnl_2/socket.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *	http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include <errno.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#include "netlink-types.h"
-
-/* Join group */
-int nl_socket_add_membership(struct nl_sock *sk, int group)
-{
-	return setsockopt(sk->s_fd, SOL_NETLINK,
-			NETLINK_ADD_MEMBERSHIP, &group, sizeof(group));
-}
-
-/* Allocate new netlink socket. */
-static struct nl_sock *_nl_socket_alloc(void)
-{
-	struct nl_sock *sk;
-	struct timeval tv;
-	struct nl_cb *cb;
-
-	sk = (struct nl_sock *) malloc(sizeof(struct nl_sock));
-	if (!sk)
-		return NULL;
-	memset(sk, 0, sizeof(*sk));
-
-	/* Get current time */
-
-	if (gettimeofday(&tv, NULL))
-		goto fail;
-	else
-		sk->s_seq_next = (int) tv.tv_sec;
-
-	/* Create local socket */
-	sk->s_local.nl_family = AF_NETLINK;
-	sk->s_local.nl_pid = 0; /* Kernel fills in pid */
-	sk->s_local.nl_groups = 0; /* No groups */
-
-	/* Create peer socket */
-	sk->s_peer.nl_family = AF_NETLINK;
-	sk->s_peer.nl_pid = 0; /* Kernel */
-	sk->s_peer.nl_groups = 0; /* No groups */
-
-	return sk;
-fail:
-	free(sk);
-	return NULL;
-}
-
-/* Allocate new netlink socket. */
-struct nl_sock *nl_socket_alloc(void)
-{
-	struct nl_sock *sk = _nl_socket_alloc();
-	struct nl_cb *cb;
-
-	if (!sk)
-		return NULL;
-
-	cb = nl_cb_alloc(NL_CB_DEFAULT);
-	if (!cb)
-		goto cb_fail;
-	sk->s_cb = cb;
-	return sk;
-cb_fail:
-	free(sk);
-	return NULL;
-}
-
-/* Allocate new socket with custom callbacks. */
-struct nl_sock *nl_socket_alloc_cb(struct nl_cb *cb)
-{
-	struct nl_sock *sk = _nl_socket_alloc();
-
-	if (!sk)
-		return NULL;
-
-	sk->s_cb = cb;
-	nl_cb_get(cb);
-
-	return sk;
-}
-
-/* Free a netlink socket. */
-void nl_socket_free(struct nl_sock *sk)
-{
-	nl_cb_put(sk->s_cb);
-	close(sk->s_fd);
-	free(sk);
-}
-
-/* Sets socket buffer size of netlink socket */
-int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf)
-{
-	if (setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF, \
-			&rxbuf, (socklen_t) sizeof(rxbuf)))
-		goto error;
-
-	if (setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF, \
-			&txbuf, (socklen_t) sizeof(txbuf)))
-		goto error;
-
-	return 0;
-error:
-	return -errno;
-
-}
-
-int nl_socket_get_fd(struct nl_sock *sk)
-{
-	return sk->s_fd;
-}
-
-void nl_socket_set_cb(struct nl_sock *sk, struct nl_cb *cb)
-{
-	nl_cb_put(sk->s_cb);
-	sk->s_cb = cb;
-	nl_cb_get(cb);
-}
-
-struct nl_cb *nl_socket_get_cb(struct nl_sock *sk)
-{
-	return nl_cb_get(sk->s_cb);
-}
diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk
index fe50cc6..484cf50 100644
--- a/libpixelflinger/Android.mk
+++ b/libpixelflinger/Android.mk
@@ -7,13 +7,13 @@
 
 include $(CLEAR_VARS)
 PIXELFLINGER_SRC_FILES:= \
-    codeflinger/ARMAssemblerInterface.cpp \
-    codeflinger/ARMAssemblerProxy.cpp \
-    codeflinger/CodeCache.cpp \
-    codeflinger/GGLAssembler.cpp \
-    codeflinger/load_store.cpp \
-    codeflinger/blending.cpp \
-    codeflinger/texturing.cpp \
+	codeflinger/ARMAssemblerInterface.cpp \
+	codeflinger/ARMAssemblerProxy.cpp \
+	codeflinger/CodeCache.cpp \
+	codeflinger/GGLAssembler.cpp \
+	codeflinger/load_store.cpp \
+	codeflinger/blending.cpp \
+	codeflinger/texturing.cpp \
 	codeflinger/tinyutils/SharedBuffer.cpp \
 	codeflinger/tinyutils/VectorImpl.cpp \
 	fixed.cpp.arm \
@@ -26,39 +26,28 @@
 	raster.cpp \
 	buffer.cpp
 
-ifeq ($(TARGET_ARCH),arm)
-ifeq ($(TARGET_ARCH_VERSION),armv7-a)
-PIXELFLINGER_SRC_FILES += col32cb16blend_neon.S
-PIXELFLINGER_SRC_FILES += col32cb16blend.S
-else
-PIXELFLINGER_SRC_FILES += t32cb16blend.S
-PIXELFLINGER_SRC_FILES += col32cb16blend.S
-endif
+PIXELFLINGER_CFLAGS := -fstrict-aliasing -fomit-frame-pointer
+
+PIXELFLINGER_SRC_FILES_arm := \
+	codeflinger/ARMAssembler.cpp \
+	codeflinger/disassem.c \
+	col32cb16blend.S \
+	t32cb16blend.S \
+
+ifeq ($(ARCH_ARM_HAVE_NEON),true)
+PIXELFLINGER_SRC_FILES_arm += col32cb16blend_neon.S
 endif
 
-ifeq ($(TARGET_ARCH),arm)
-PIXELFLINGER_SRC_FILES += codeflinger/ARMAssembler.cpp
-PIXELFLINGER_SRC_FILES += codeflinger/disassem.c
-# special optimization flags for pixelflinger
-PIXELFLINGER_CFLAGS += -fstrict-aliasing -fomit-frame-pointer
-endif
+PIXELFLINGER_SRC_FILES_arm64 := \
+	codeflinger/Arm64Assembler.cpp \
+	codeflinger/Arm64Disassembler.cpp \
+	arch-arm64/col32cb16blend.S \
+	arch-arm64/t32cb16blend.S \
 
-ifeq ($(TARGET_ARCH),mips)
-PIXELFLINGER_SRC_FILES += codeflinger/MIPSAssembler.cpp
-PIXELFLINGER_SRC_FILES += codeflinger/mips_disassem.c
-PIXELFLINGER_SRC_FILES += arch-mips/t32cb16blend.S
-PIXELFLINGER_CFLAGS += -fstrict-aliasing -fomit-frame-pointer
-endif
-
-LOCAL_SHARED_LIBRARIES := libcutils liblog
-
-ifeq ($(TARGET_ARCH),arm64)
-PIXELFLINGER_SRC_FILES += arch-arm64/t32cb16blend.S
-PIXELFLINGER_SRC_FILES += arch-arm64/col32cb16blend.S
-PIXELFLINGER_SRC_FILES += codeflinger/Arm64Assembler.cpp
-PIXELFLINGER_SRC_FILES += codeflinger/Arm64Disassembler.cpp
-PIXELFLINGER_CFLAGS += -fstrict-aliasing -fomit-frame-pointer
-endif
+PIXELFLINGER_SRC_FILES_mips := \
+	codeflinger/MIPSAssembler.cpp \
+	codeflinger/mips_disassem.c \
+	arch-mips/t32cb16blend.S \
 
 #
 # Shared library
@@ -66,7 +55,11 @@
 
 LOCAL_MODULE:= libpixelflinger
 LOCAL_SRC_FILES := $(PIXELFLINGER_SRC_FILES)
+LOCAL_SRC_FILES_arm := $(PIXELFLINGER_SRC_FILES_arm)
+LOCAL_SRC_FILES_arm64 := $(PIXELFLINGER_SRC_FILES_arm64)
+LOCAL_SRC_FILES_mips := $(PIXELFLINGER_SRC_FILES_mips)
 LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS)
+LOCAL_SHARED_LIBRARIES := libcutils liblog
 
 ifneq ($(BUILD_TINY_ANDROID),true)
 # Really this should go away entirely or at least not depend on
@@ -83,6 +76,9 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE:= libpixelflinger_static
 LOCAL_SRC_FILES := $(PIXELFLINGER_SRC_FILES)
+LOCAL_SRC_FILES_arm := $(PIXELFLINGER_SRC_FILES_arm)
+LOCAL_SRC_FILES_arm64 := $(PIXELFLINGER_SRC_FILES_arm64)
+LOCAL_SRC_FILES_mips := $(PIXELFLINGER_SRC_FILES_mips)
 LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS)
 include $(BUILD_STATIC_LIBRARY)
 
diff --git a/libpixelflinger/buffer.cpp b/libpixelflinger/buffer.cpp
index cbdab5a..dcb95c5 100644
--- a/libpixelflinger/buffer.cpp
+++ b/libpixelflinger/buffer.cpp
@@ -130,7 +130,7 @@
     }
 }
 
-void readRGB565(const surface_t* s, context_t* c,
+void readRGB565(const surface_t* s, context_t* /*c*/,
         uint32_t x, uint32_t y, pixel_t* pixel)
 {
     uint16_t v = *(reinterpret_cast<uint16_t*>(s->data) + (x + (s->stride * y)));
@@ -144,7 +144,7 @@
     pixel->s[3] = 5;
 }
 
-void readABGR8888(const surface_t* s, context_t* c,
+void readABGR8888(const surface_t* s, context_t* /*c*/,
         uint32_t x, uint32_t y, pixel_t* pixel)
 {
     uint32_t v = *(reinterpret_cast<uint32_t*>(s->data) + (x + (s->stride * y)));
diff --git a/libpixelflinger/codeflinger/Arm64Assembler.cpp b/libpixelflinger/codeflinger/Arm64Assembler.cpp
index f37072a..bd11818 100644
--- a/libpixelflinger/codeflinger/Arm64Assembler.cpp
+++ b/libpixelflinger/codeflinger/Arm64Assembler.cpp
@@ -273,7 +273,7 @@
     *mPC++ = (0x54 << 24) | cc;
 }
 
-void ArmToArm64Assembler::BL(int cc, const char* label)
+void ArmToArm64Assembler::BL(int /*cc*/, const char* /*label*/)
 {
     NOT_IMPLEMENTED(); //Not Required
 }
@@ -289,7 +289,7 @@
     *mPC++ = A64_MOVZ_X(mZeroReg,0,0);
 }
 
-void ArmToArm64Assembler::epilog(uint32_t touched)
+void ArmToArm64Assembler::epilog(uint32_t /*touched*/)
 {
     // write epilog code
     static const int XLR = 30;
@@ -530,23 +530,23 @@
     if(s  != 0) { NOT_IMPLEMENTED(); return;} //Not required
     *mPC++ = A64_MADD_W(Rd, Rm, Rs, mZeroReg);
 }
-void ArmToArm64Assembler::UMULL(int cc, int s,
-        int RdLo, int RdHi, int Rm, int Rs)
+void ArmToArm64Assembler::UMULL(int /*cc*/, int /*s*/,
+        int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
-void ArmToArm64Assembler::UMUAL(int cc, int s,
-        int RdLo, int RdHi, int Rm, int Rs)
+void ArmToArm64Assembler::UMUAL(int /*cc*/, int /*s*/,
+        int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
-void ArmToArm64Assembler::SMULL(int cc, int s,
-        int RdLo, int RdHi, int Rm, int Rs)
+void ArmToArm64Assembler::SMULL(int /*cc*/, int /*s*/,
+        int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
-void ArmToArm64Assembler::SMUAL(int cc, int s,
-        int RdLo, int RdHi, int Rm, int Rs)
+void ArmToArm64Assembler::SMUAL(int /*cc*/, int /*s*/,
+        int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
@@ -554,15 +554,15 @@
 // ----------------------------------------------------------------------------
 // branches relative to PC...
 // ----------------------------------------------------------------------------
-void ArmToArm64Assembler::B(int cc, uint32_t* pc){
+void ArmToArm64Assembler::B(int /*cc*/, uint32_t* /*pc*/){
     NOT_IMPLEMENTED(); //Not required
 }
 
-void ArmToArm64Assembler::BL(int cc, uint32_t* pc){
+void ArmToArm64Assembler::BL(int /*cc*/, uint32_t* /*pc*/){
     NOT_IMPLEMENTED(); //Not required
 }
 
-void ArmToArm64Assembler::BX(int cc, int Rn){
+void ArmToArm64Assembler::BX(int /*cc*/, int /*Rn*/){
     NOT_IMPLEMENTED(); //Not required
 }
 
@@ -661,11 +661,11 @@
 {
     return dataTransfer(opLDRH, cc, Rd, Rn, op_type);
 }
-void ArmToArm64Assembler::LDRSB(int cc, int Rd, int Rn, uint32_t offset)
+void ArmToArm64Assembler::LDRSB(int /*cc*/, int /*Rd*/, int /*Rn*/, uint32_t /*offset*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
-void ArmToArm64Assembler::LDRSH(int cc, int Rd, int Rn, uint32_t offset)
+void ArmToArm64Assembler::LDRSH(int /*cc*/, int /*Rd*/, int /*Rn*/, uint32_t /*offset*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
@@ -723,15 +723,15 @@
 // ----------------------------------------------------------------------------
 // special...
 // ----------------------------------------------------------------------------
-void ArmToArm64Assembler::SWP(int cc, int Rn, int Rd, int Rm)
+void ArmToArm64Assembler::SWP(int /*cc*/, int /*Rn*/, int /*Rd*/, int /*Rm*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
-void ArmToArm64Assembler::SWPB(int cc, int Rn, int Rd, int Rm)
+void ArmToArm64Assembler::SWPB(int /*cc*/, int /*Rn*/, int /*Rd*/, int /*Rm*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
-void ArmToArm64Assembler::SWI(int cc, uint32_t comment)
+void ArmToArm64Assembler::SWI(int /*cc*/, uint32_t /*comment*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
@@ -739,31 +739,31 @@
 // ----------------------------------------------------------------------------
 // DSP instructions...
 // ----------------------------------------------------------------------------
-void ArmToArm64Assembler::PLD(int Rn, uint32_t offset) {
+void ArmToArm64Assembler::PLD(int /*Rn*/, uint32_t /*offset*/) {
     NOT_IMPLEMENTED(); //Not required
 }
 
-void ArmToArm64Assembler::CLZ(int cc, int Rd, int Rm)
+void ArmToArm64Assembler::CLZ(int /*cc*/, int /*Rd*/, int /*Rm*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
 
-void ArmToArm64Assembler::QADD(int cc,  int Rd, int Rm, int Rn)
+void ArmToArm64Assembler::QADD(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
 
-void ArmToArm64Assembler::QDADD(int cc,  int Rd, int Rm, int Rn)
+void ArmToArm64Assembler::QDADD(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
 
-void ArmToArm64Assembler::QSUB(int cc,  int Rd, int Rm, int Rn)
+void ArmToArm64Assembler::QSUB(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
 
-void ArmToArm64Assembler::QDSUB(int cc,  int Rd, int Rm, int Rn)
+void ArmToArm64Assembler::QDSUB(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
@@ -817,15 +817,15 @@
     *mPC++ = A64_MADD_W(Rd, mTmpReg1, mTmpReg2, Rn);
 }
 
-void ArmToArm64Assembler::SMLAL(int cc, int xy,
-                int RdHi, int RdLo, int Rs, int Rm)
+void ArmToArm64Assembler::SMLAL(int /*cc*/, int /*xy*/,
+                int /*RdHi*/, int /*RdLo*/, int /*Rs*/, int /*Rm*/)
 {
     NOT_IMPLEMENTED(); //Not required
     return;
 }
 
-void ArmToArm64Assembler::SMLAW(int cc, int y,
-                int Rd, int Rm, int Rs, int Rn)
+void ArmToArm64Assembler::SMLAW(int /*cc*/, int /*y*/,
+                int /*Rd*/, int /*Rm*/, int /*Rs*/, int /*Rn*/)
 {
     NOT_IMPLEMENTED(); //Not required
     return;
@@ -890,13 +890,13 @@
     return OPERAND_REG_IMM;
 }
 
-uint32_t ArmToArm64Assembler::reg_rrx(int Rm)
+uint32_t ArmToArm64Assembler::reg_rrx(int /*Rm*/)
 {
     NOT_IMPLEMENTED();
     return OPERAND_UNSUPPORTED;
 }
 
-uint32_t ArmToArm64Assembler::reg_reg(int Rm, int type, int Rs)
+uint32_t ArmToArm64Assembler::reg_reg(int /*Rm*/, int /*type*/, int /*Rs*/)
 {
     NOT_IMPLEMENTED(); //Not required
     return OPERAND_UNSUPPORTED;
@@ -937,7 +937,7 @@
     }
 }
 
-uint32_t ArmToArm64Assembler::reg_scale_post(int Rm, int type, uint32_t shift)
+uint32_t ArmToArm64Assembler::reg_scale_post(int /*Rm*/, int /*type*/, uint32_t /*shift*/)
 {
     NOT_IMPLEMENTED(); //Not required
     return OPERAND_UNSUPPORTED;
@@ -975,7 +975,7 @@
     }
 }
 
-uint32_t ArmToArm64Assembler::reg_post(int Rm)
+uint32_t ArmToArm64Assembler::reg_post(int /*Rm*/)
 {
     NOT_IMPLEMENTED(); //Not required
     return OPERAND_UNSUPPORTED;
diff --git a/libpixelflinger/codeflinger/CodeCache.cpp b/libpixelflinger/codeflinger/CodeCache.cpp
index 4fe30d9..cfd2b37 100644
--- a/libpixelflinger/codeflinger/CodeCache.cpp
+++ b/libpixelflinger/codeflinger/CodeCache.cpp
@@ -89,7 +89,7 @@
         gExecutableStore = mmap(NULL, kMaxCodeCacheCapacity,
                                 PROT_READ | PROT_WRITE | PROT_EXEC,
                                 MAP_PRIVATE, fd, 0);
-        LOG_ALWAYS_FATAL_IF(gExecutableStore == NULL,
+        LOG_ALWAYS_FATAL_IF(gExecutableStore == MAP_FAILED,
                             "Creating code cache, mmap failed with error "
                             "'%s'", strerror(errno));
         close(fd);
@@ -201,13 +201,9 @@
         mCacheInUse += assemblySize;
         mWhen++;
         // synchronize caches...
-#if defined(__arm__) || defined(__mips__) || defined(__aarch64__)
-        const long base = long(assembly->base());
-        const long curr = base + long(assembly->size());
-        err = cacheflush(base, curr, 0);
-        ALOGE_IF(err, "cacheflush error %s\n",
-                 strerror(errno));
-#endif
+        void* base = assembly->base();
+        void* curr = (uint8_t*)base + assembly->size();
+        __builtin___clear_cache(base, curr);
     }
 
     pthread_mutex_unlock(&mLock);
diff --git a/libpixelflinger/codeflinger/GGLAssembler.cpp b/libpixelflinger/codeflinger/GGLAssembler.cpp
index 2422d7b..325caba 100644
--- a/libpixelflinger/codeflinger/GGLAssembler.cpp
+++ b/libpixelflinger/codeflinger/GGLAssembler.cpp
@@ -694,7 +694,7 @@
 // ---------------------------------------------------------------------------
 
 void GGLAssembler::build_alpha_test(component_t& fragment,
-                                    const fragment_parts_t& parts)
+                                    const fragment_parts_t& /*parts*/)
 {
     if (mAlphaTest != GGL_ALWAYS) {
         comment("Alpha Test");
@@ -796,7 +796,7 @@
     }
 }
 
-void GGLAssembler::build_iterate_f(const fragment_parts_t& parts)
+void GGLAssembler::build_iterate_f(const fragment_parts_t& /*parts*/)
 {
     const needs_t& needs = mBuilderContext.needs;
     if (GGL_READ_NEEDS(P_FOG, needs.p)) {
diff --git a/libpixelflinger/codeflinger/disassem.c b/libpixelflinger/codeflinger/disassem.c
index aeb8034..39dd614 100644
--- a/libpixelflinger/codeflinger/disassem.c
+++ b/libpixelflinger/codeflinger/disassem.c
@@ -301,19 +301,14 @@
 static void disassemble_printaddr(u_int address);
 
 u_int
-disasm(const disasm_interface_t *di, u_int loc, int altfmt)
+disasm(const disasm_interface_t *di, u_int loc, int __unused altfmt)
 {
 	const struct arm32_insn *i_ptr = &arm32_i[0];
-
-	u_int insn;
-	int matchp;
+	u_int insn = di->di_readword(loc);
+	int matchp = 0;
 	int branch;
 	char* f_ptr;
-	int fmt;
-
-	fmt = 0;
-	matchp = 0;
-	insn = di->di_readword(loc);
+	int fmt = 0;
 
 /*	di->di_printf("loc=%08x insn=%08x : ", loc, insn);*/
 
@@ -670,7 +665,7 @@
 }
 
 static void
-disasm_insn_ldcstc(const disasm_interface_t *di, u_int insn, u_int loc)
+disasm_insn_ldcstc(const disasm_interface_t *di, u_int insn, u_int __unused loc)
 {
 	if (((insn >> 8) & 0xf) == 1)
 		di->di_printf("f%d, ", (insn >> 12) & 0x07);
diff --git a/libpixelflinger/codeflinger/disassem.h b/libpixelflinger/codeflinger/disassem.h
index 02747cd..c7c60b6 100644
--- a/libpixelflinger/codeflinger/disassem.h
+++ b/libpixelflinger/codeflinger/disassem.h
@@ -49,8 +49,8 @@
 
 typedef struct {
 	u_int	(*di_readword)(u_int);
-	void	(*di_printaddr)(u_int);	
-	void	(*di_printf)(const char *, ...);
+	void	(*di_printaddr)(u_int);
+	int	(*di_printf)(const char *, ...);
 } disasm_interface_t;
 
 /* Prototypes for callable functions */
diff --git a/libpixelflinger/codeflinger/texturing.cpp b/libpixelflinger/codeflinger/texturing.cpp
index b2cfbb3..81950bf 100644
--- a/libpixelflinger/codeflinger/texturing.cpp
+++ b/libpixelflinger/codeflinger/texturing.cpp
@@ -694,7 +694,7 @@
 }
 
 void GGLAssembler::filter8(
-        const fragment_parts_t& parts,
+        const fragment_parts_t& /*parts*/,
         pixel_t& texel, const texture_unit_t& tmu,
         int U, int V, pointer_t& txPtr,
         int FRAC_BITS)
@@ -761,7 +761,7 @@
 }
 
 void GGLAssembler::filter16(
-        const fragment_parts_t& parts,
+        const fragment_parts_t& /*parts*/,
         pixel_t& texel, const texture_unit_t& tmu,
         int U, int V, pointer_t& txPtr,
         int FRAC_BITS)
@@ -879,10 +879,10 @@
 }
 
 void GGLAssembler::filter24(
-        const fragment_parts_t& parts,
-        pixel_t& texel, const texture_unit_t& tmu,
-        int U, int V, pointer_t& txPtr,
-        int FRAC_BITS)
+        const fragment_parts_t& /*parts*/,
+        pixel_t& texel, const texture_unit_t& /*tmu*/,
+        int /*U*/, int /*V*/, pointer_t& txPtr,
+        int /*FRAC_BITS*/)
 {
     // not supported yet (currently disabled)
     load(txPtr, texel, 0);
@@ -989,8 +989,8 @@
 }
 #else
 void GGLAssembler::filter32(
-        const fragment_parts_t& parts,
-        pixel_t& texel, const texture_unit_t& tmu,
+        const fragment_parts_t& /*parts*/,
+        pixel_t& texel, const texture_unit_t& /*tmu*/,
         int U, int V, pointer_t& txPtr,
         int FRAC_BITS)
 {
diff --git a/libpixelflinger/picker.cpp b/libpixelflinger/picker.cpp
index 030ef19..aa55229 100644
--- a/libpixelflinger/picker.cpp
+++ b/libpixelflinger/picker.cpp
@@ -26,7 +26,7 @@
 
 // ----------------------------------------------------------------------------
 
-void ggl_init_picker(context_t* c)
+void ggl_init_picker(context_t* /*c*/)
 {
 }
 
diff --git a/libpixelflinger/pixelflinger.cpp b/libpixelflinger/pixelflinger.cpp
index 84e584e..ea5bc8e 100644
--- a/libpixelflinger/pixelflinger.cpp
+++ b/libpixelflinger/pixelflinger.cpp
@@ -662,7 +662,7 @@
     }
 }
 
-void ggl_enable_stencil_test(context_t* c, int enable)
+void ggl_enable_stencil_test(context_t* /*c*/, int /*enable*/)
 {
 }
 
diff --git a/libpixelflinger/raster.cpp b/libpixelflinger/raster.cpp
index 32b2a97..26d8e45 100644
--- a/libpixelflinger/raster.cpp
+++ b/libpixelflinger/raster.cpp
@@ -51,7 +51,7 @@
 }
 
 void ggl_copyPixels(void* con, GGLint xs, GGLint ys,
-        GGLsizei width, GGLsizei height, GGLenum type)
+        GGLsizei width, GGLsizei height, GGLenum /*type*/)
 {
     GGL_CONTEXT(c, con);
 
diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp
index aa23ca6..26b9a3e 100644
--- a/libpixelflinger/scanline.cpp
+++ b/libpixelflinger/scanline.cpp
@@ -26,6 +26,10 @@
 #include <cutils/memory.h>
 #include <cutils/log.h>
 
+#ifdef __arm__
+#include <machine/cpu-features.h>
+#endif
+
 #include "buffer.h"
 #include "scanline.h"
 
@@ -35,7 +39,7 @@
 #include "codeflinger/ARMAssembler.h"
 #elif defined(__aarch64__)
 #include "codeflinger/Arm64Assembler.h"
-#elif defined(__mips__)
+#elif defined(__mips__) && !defined(__LP64__)
 #include "codeflinger/MIPSAssembler.h"
 #endif
 //#include "codeflinger/ARMAssemblerOptimizer.h"
@@ -55,7 +59,7 @@
 #   define ANDROID_CODEGEN      ANDROID_CODEGEN_GENERATED
 #endif
 
-#if defined(__arm__) || defined(__mips__) || defined(__aarch64__)
+#if defined(__arm__) || (defined(__mips__) && !defined(__LP64__)) || defined(__aarch64__)
 #   define ANDROID_ARM_CODEGEN  1
 #else
 #   define ANDROID_ARM_CODEGEN  0
@@ -69,7 +73,7 @@
  */
 #define DEBUG_NEEDS  0
 
-#ifdef __mips__
+#if defined( __mips__) && !defined(__LP64__)
 #define ASSEMBLY_SCRATCH_SIZE   4096
 #elif defined(__aarch64__)
 #define ASSEMBLY_SCRATCH_SIZE   8192
@@ -130,7 +134,7 @@
 #elif defined(__aarch64__)
 extern "C" void scanline_t32cb16blend_arm64(uint16_t*, uint32_t*, size_t);
 extern "C" void scanline_col32cb16blend_arm64(uint16_t *dst, uint32_t col, size_t ct);
-#elif defined(__mips__)
+#elif defined(__mips__)  && !defined(__LP64__)
 extern "C" void scanline_t32cb16blend_mips(uint16_t*, uint32_t*, size_t);
 #endif
 
@@ -408,10 +412,10 @@
         GGLAssembler assembler( new ArmToArm64Assembler(a) );
 #endif
         // generate the scanline code for the given needs
-        int err = assembler.scanline(c->state.needs, c);
+        bool err = assembler.scanline(c->state.needs, c) != 0;
         if (ggl_likely(!err)) {
             // finally, cache this assembly
-            err = gCodeCache.cache(a->key(), a);
+            err = gCodeCache.cache(a->key(), a) < 0;
         }
         if (ggl_unlikely(err)) {
             ALOGE("error generating or caching assembly. Reverting to NOP.");
@@ -534,7 +538,7 @@
     return x;
 }
 
-void blend_factor(context_t* c, pixel_t* r, 
+void blend_factor(context_t* /*c*/, pixel_t* r, 
         uint32_t factor, const pixel_t* src, const pixel_t* dst)
 {
     switch (factor) {
@@ -1161,7 +1165,7 @@
  *   blender.blend(<32-bit-src-pixel-value>,<ptr-to-16-bit-dest-pixel>)
  */
 struct blender_32to16 {
-    blender_32to16(context_t* c) { }
+    blender_32to16(context_t* /*c*/) { }
     void write(uint32_t s, uint16_t* dst) {
         if (s == 0)
             return;
@@ -1218,7 +1222,7 @@
  * where dstFactor=srcA*(1-srcA) srcFactor=srcA
  */
 struct blender_32to16_srcA {
-    blender_32to16_srcA(const context_t* c) { }
+    blender_32to16_srcA(const context_t* /*c*/) { }
     void write(uint32_t s, uint16_t* dst) {
         if (!s) {
             return;
@@ -2171,7 +2175,7 @@
 
 void scanline_t32cb16blend(context_t* c)
 {
-#if ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && (defined(__arm__) || defined(__mips__) || defined(__aarch64__)))
+#if ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && (defined(__arm__) || (defined(__mips__) && !defined(__LP64__)) || defined(__aarch64__)))
     int32_t x = c->iterators.xl;
     size_t ct = c->iterators.xr - x;
     int32_t y = c->iterators.y;
@@ -2317,7 +2321,7 @@
     memset(dst, 0xFF, size);
 }
 
-void scanline_noop(context_t* c)
+void scanline_noop(context_t* /*c*/)
 {
 }
 
diff --git a/libpixelflinger/tests/arch-arm64/assembler/Android.mk b/libpixelflinger/tests/arch-arm64/assembler/Android.mk
index 36db49c..eca36ef 100644
--- a/libpixelflinger/tests/arch-arm64/assembler/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/assembler/Android.mk
@@ -16,4 +16,6 @@
 
 LOCAL_MODULE_TAGS := tests
 
-include $(BUILD_EXECUTABLE)
+LOCAL_MULTILIB := 64
+
+include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp b/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp
index 84381d5..456be58 100644
--- a/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp
+++ b/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp
@@ -405,11 +405,11 @@
 };
 
 
-int flushcache()
+void flushcache()
 {
     const long base = long(instrMem);
     const long curr = base + long(instrMemSize);
-    return cacheflush(base, curr, 0);
+    __builtin___clear_cache((void*)base, (void*)curr);
 }
 void dataOpTest(dataOpTest_t test, ARMAssemblerInterface *a64asm, uint32_t Rd = 0,
                 uint32_t Rn = 1, uint32_t Rm = 2, uint32_t Rs = 3)
diff --git a/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk b/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
index ac890c7..3368eb0 100644
--- a/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
@@ -13,4 +13,6 @@
 
 LOCAL_MODULE_TAGS := tests
 
-include $(BUILD_EXECUTABLE)
+LOCAL_MULTILIB := 64
+
+include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/arch-arm64/disassembler/Android.mk b/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
index baf4070..8f62f09 100644
--- a/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
@@ -14,4 +14,6 @@
 
 LOCAL_MODULE_TAGS := tests
 
-include $(BUILD_EXECUTABLE)
+LOCAL_MULTILIB := 64
+
+include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
index 1cce1bd..8e5ec5e 100644
--- a/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
@@ -13,4 +13,6 @@
 
 LOCAL_MODULE_TAGS := tests
 
-include $(BUILD_EXECUTABLE)
+LOCAL_MULTILIB := 64
+
+include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/codegen/Android.mk b/libpixelflinger/tests/codegen/Android.mk
index aa320fc..bc07015 100644
--- a/libpixelflinger/tests/codegen/Android.mk
+++ b/libpixelflinger/tests/codegen/Android.mk
@@ -15,4 +15,4 @@
 
 LOCAL_MODULE_TAGS := tests
 
-include $(BUILD_EXECUTABLE)
+include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/codegen/codegen.cpp b/libpixelflinger/tests/codegen/codegen.cpp
index e9f6c61..46c1ccc 100644
--- a/libpixelflinger/tests/codegen/codegen.cpp
+++ b/libpixelflinger/tests/codegen/codegen.cpp
@@ -52,7 +52,7 @@
     GGLAssembler assembler( new ARMAssembler(a) );
 #endif
 
-#if defined(__mips__)
+#if defined(__mips__) && !defined(__LP64__)
     GGLAssembler assembler( new ArmToMipsAssembler(a) );
 #endif
 
diff --git a/libpixelflinger/tests/gglmul/Android.mk b/libpixelflinger/tests/gglmul/Android.mk
index 64f88b7..f479fa1 100644
--- a/libpixelflinger/tests/gglmul/Android.mk
+++ b/libpixelflinger/tests/gglmul/Android.mk
@@ -13,4 +13,4 @@
 
 LOCAL_MODULE_TAGS := tests
 
-include $(BUILD_EXECUTABLE)
+include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/gglmul/gglmul_test.cpp b/libpixelflinger/tests/gglmul/gglmul_test.cpp
index 073368e..5d460d6 100644
--- a/libpixelflinger/tests/gglmul/gglmul_test.cpp
+++ b/libpixelflinger/tests/gglmul/gglmul_test.cpp
@@ -28,6 +28,7 @@
 
 #include <stdio.h>
 #include <stdint.h>
+#include <inttypes.h>
 
 #include "private/pixelflinger/ggl_fixed.h"
 
@@ -260,12 +261,12 @@
         if(actual == expected)
             printf(" Passed\n");
         else
-            printf(" Failed Actual(%ld) Expected(%ld)\n",
+            printf(" Failed Actual(%" PRId64 ") Expected(%" PRId64 ")\n",
                     actual, expected);
     }
 }
 
-int main(int argc, char** argv)
+int main(int /*argc*/, char** /*argv*/)
 {
     gglClampx_test();
     gglClz_test();
diff --git a/libsparse/Android.mk b/libsparse/Android.mk
index 9025cc0..02ab412 100644
--- a/libsparse/Android.mk
+++ b/libsparse/Android.mk
@@ -17,6 +17,7 @@
 LOCAL_MODULE := libsparse_host
 LOCAL_STATIC_LIBRARIES := libz
 LOCAL_C_INCLUDES += $(LOCAL_PATH)/include external/zlib
+LOCAL_CFLAGS := -Werror
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 
@@ -27,6 +28,7 @@
 LOCAL_C_INCLUDES += $(LOCAL_PATH)/include external/zlib
 LOCAL_SHARED_LIBRARIES := \
     libz
+LOCAL_CFLAGS := -Werror
 include $(BUILD_SHARED_LIBRARY)
 
 
@@ -36,6 +38,7 @@
 LOCAL_MODULE := libsparse_static
 LOCAL_C_INCLUDES += $(LOCAL_PATH)/include external/zlib
 LOCAL_STATIC_LIBRARIES := libz
+LOCAL_CFLAGS := -Werror
 include $(BUILD_STATIC_LIBRARY)
 
 
@@ -48,6 +51,7 @@
 LOCAL_STATIC_LIBRARIES := \
     libsparse_host \
     libz
+LOCAL_CFLAGS := -Werror
 include $(BUILD_HOST_EXECUTABLE)
 
 
@@ -58,6 +62,7 @@
 LOCAL_STATIC_LIBRARIES := \
     libsparse_static \
     libz
+LOCAL_CFLAGS := -Werror
 include $(BUILD_EXECUTABLE)
 
 
@@ -69,6 +74,7 @@
 LOCAL_STATIC_LIBRARIES := \
     libsparse_host \
     libz
+LOCAL_CFLAGS := -Werror
 include $(BUILD_HOST_EXECUTABLE)
 
 
@@ -78,6 +84,7 @@
 LOCAL_STATIC_LIBRARIES := \
     libsparse_static \
     libz
+LOCAL_CFLAGS := -Werror
 include $(BUILD_EXECUTABLE)
 
 
@@ -87,6 +94,7 @@
 LOCAL_STATIC_LIBRARIES := \
     libsparse_host \
     libz
+LOCAL_CFLAGS := -Werror
 include $(BUILD_HOST_EXECUTABLE)
 
 
@@ -95,5 +103,5 @@
 LOCAL_SRC_FILES := simg_dump.py
 LOCAL_MODULE_CLASS := EXECUTABLES
 LOCAL_IS_HOST_MODULE := true
+LOCAL_CFLAGS := -Werror
 include $(BUILD_PREBUILT)
-
diff --git a/libnl_2/cache.c b/libsparse/defs.h
similarity index 63%
copy from libnl_2/cache.c
copy to libsparse/defs.h
index c21974d..34e63c5 100644
--- a/libnl_2/cache.c
+++ b/libsparse/defs.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2014 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,24 +14,10 @@
  * limitations under the License.
  */
 
-/* NOTICE: This is a clean room re-implementation of libnl */
+#ifndef _LIBSPARSE_DEFS_H_
 
-#include "netlink/cache.h"
-#include "netlink/object.h"
+#ifndef __unused
+#define __unused        __attribute__((__unused__))
+#endif
 
-void nl_cache_free(struct nl_cache *cache)
-{
-
-}
-
-void nl_cache_clear(struct nl_cache *cache)
-{
-
-}
-
-void nl_cache_remove(struct nl_object *obj)
-{
-
-}
-
-
+#endif /* _LIBSPARSE_DEFS_H_ */
diff --git a/libsparse/img2simg.c b/libsparse/img2simg.c
index 6b1caa5..a0db36f 100644
--- a/libsparse/img2simg.c
+++ b/libsparse/img2simg.c
@@ -47,7 +47,6 @@
 {
 	int in;
 	int out;
-	unsigned int i;
 	int ret;
 	struct sparse_file *s;
 	unsigned int block_size = 4096;
diff --git a/libsparse/include/sparse/sparse.h b/libsparse/include/sparse/sparse.h
index 17d085c..8b757d2 100644
--- a/libsparse/include/sparse/sparse.h
+++ b/libsparse/include/sparse/sparse.h
@@ -20,6 +20,10 @@
 #include <stdbool.h>
 #include <stdint.h>
 
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
 struct sparse_file;
 
 /**
@@ -273,4 +277,8 @@
  */
 extern void (*sparse_print_verbose)(const char *fmt, ...);
 
+#ifdef	__cplusplus
+}
+#endif
+
 #endif
diff --git a/libsparse/output_file.c b/libsparse/output_file.c
index e63c4a9..cd30800 100644
--- a/libsparse/output_file.c
+++ b/libsparse/output_file.c
@@ -29,9 +29,10 @@
 #include <unistd.h>
 #include <zlib.h>
 
+#include "defs.h"
 #include "output_file.h"
-#include "sparse_format.h"
 #include "sparse_crc32.h"
+#include "sparse_format.h"
 
 #ifndef USE_MINGW
 #include <sys/mman.h>
@@ -264,7 +265,7 @@
 	.close = gz_file_close,
 };
 
-static int callback_file_open(struct output_file *out, int fd)
+static int callback_file_open(struct output_file *out __unused, int fd __unused)
 {
 	return 0;
 }
@@ -287,14 +288,13 @@
 	return 0;
 }
 
-static int callback_file_pad(struct output_file *out, int64_t len)
+static int callback_file_pad(struct output_file *out __unused, int64_t len __unused)
 {
 	return -1;
 }
 
 static int callback_file_write(struct output_file *out, void *data, int len)
 {
-	int ret;
 	struct output_file_callback *outc = to_output_file_callback(out);
 
 	return outc->write(outc->priv, data, len);
@@ -340,7 +340,7 @@
 static int write_sparse_skip_chunk(struct output_file *out, int64_t skip_len)
 {
 	chunk_header_t chunk_header;
-	int ret, chunk;
+	int ret;
 
 	if (skip_len % out->block_size) {
 		error("don't care size %"PRIi64" is not a multiple of the block size %u",
@@ -367,9 +367,8 @@
 		uint32_t fill_val)
 {
 	chunk_header_t chunk_header;
-	int rnd_up_len, zero_len, count;
+	int rnd_up_len, count;
 	int ret;
-	unsigned int i;
 
 	/* Round up the fill length to a multiple of the block size */
 	rnd_up_len = ALIGN(len, out->block_size);
@@ -535,8 +534,6 @@
 
 void output_file_close(struct output_file *out)
 {
-	int ret;
-
 	out->sparse_ops->write_end_chunk(out);
 	out->ops->close(out);
 }
@@ -631,8 +628,8 @@
 }
 
 struct output_file *output_file_open_callback(int (*write)(void *, const void *, int),
-		void *priv, unsigned int block_size, int64_t len, int gz, int sparse,
-		int chunks, int crc)
+		void *priv, unsigned int block_size, int64_t len,
+		int gz __unused, int sparse, int chunks, int crc)
 {
 	int ret;
 	struct output_file_callback *outc;
diff --git a/libsparse/sparse.c b/libsparse/sparse.c
index 741e8c6..baa30cd 100644
--- a/libsparse/sparse.c
+++ b/libsparse/sparse.c
@@ -19,6 +19,7 @@
 
 #include <sparse/sparse.h>
 
+#include "defs.h"
 #include "sparse_file.h"
 
 #include "output_file.h"
@@ -189,7 +190,7 @@
 	return ret;
 }
 
-static int out_counter_write(void *priv, const void *data, int len)
+static int out_counter_write(void *priv, const void *data __unused, int len)
 {
 	int64_t *count = priv;
 	*count += len;
@@ -278,7 +279,6 @@
 		struct sparse_file **out_s, int out_s_count)
 {
 	struct backed_block *bb;
-	unsigned int overhead;
 	struct sparse_file *s;
 	struct sparse_file *tmp;
 	int c = 0;
diff --git a/libsparse/sparse_read.c b/libsparse/sparse_read.c
index 704bcfa..8e188e9 100644
--- a/libsparse/sparse_read.c
+++ b/libsparse/sparse_read.c
@@ -29,6 +29,8 @@
 
 #include <sparse/sparse.h>
 
+#include "defs.h"
+#include "output_file.h"
 #include "sparse_crc32.h"
 #include "sparse_file.h"
 #include "sparse_format.h"
@@ -175,24 +177,19 @@
 }
 
 static int process_skip_chunk(struct sparse_file *s, unsigned int chunk_size,
-		int fd, unsigned int blocks, unsigned int block, uint32_t *crc32)
+		int fd __unused, unsigned int blocks,
+		unsigned int block __unused, uint32_t *crc32)
 {
-	int ret;
-	int chunk;
-	int64_t len = (int64_t)blocks * s->block_size;
-	uint32_t fill_val;
-	uint32_t *fillbuf;
-	unsigned int i;
-
 	if (chunk_size != 0) {
 		return -EINVAL;
 	}
 
 	if (crc32) {
+	        int64_t len = (int64_t)blocks * s->block_size;
 		memset(copybuf, 0, COPY_BUF_SIZE);
 
 		while (len) {
-			chunk = min(len, COPY_BUF_SIZE);
+			int chunk = min(len, COPY_BUF_SIZE);
 			*crc32 = sparse_crc32(*crc32, copybuf, chunk);
 			len -= chunk;
 		}
@@ -364,7 +361,6 @@
 	int64_t remain = s->len;
 	int64_t offset = 0;
 	unsigned int to_read;
-	char *ptr;
 	unsigned int i;
 	bool sparse_block;
 
diff --git a/libsuspend/Android.mk b/libsuspend/Android.mk
index a2fa3e0..1ba2f59 100644
--- a/libsuspend/Android.mk
+++ b/libsuspend/Android.mk
@@ -18,6 +18,7 @@
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
 LOCAL_SHARED_LIBRARIES := $(libsuspend_libraries)
+LOCAL_CFLAGS := -Werror
 #LOCAL_CFLAGS += -DLOG_NDEBUG=0
 include $(BUILD_SHARED_LIBRARY)
 
@@ -27,5 +28,6 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Werror
 #LOCAL_CFLAGS += -DLOG_NDEBUG=0
 include $(BUILD_STATIC_LIBRARY)
diff --git a/libsuspend/autosuspend_earlysuspend.c b/libsuspend/autosuspend_earlysuspend.c
index 1df8c6a..2bece4c 100644
--- a/libsuspend/autosuspend_earlysuspend.c
+++ b/libsuspend/autosuspend_earlysuspend.c
@@ -75,13 +75,8 @@
     return err < 0 ? err : 0;
 }
 
-static void *earlysuspend_thread_func(void *arg)
+static void *earlysuspend_thread_func(void __unused *arg)
 {
-    char buf[80];
-    char wakeup_count[20];
-    int wakeup_count_len;
-    int ret;
-
     while (1) {
         if (wait_for_fb_sleep()) {
             ALOGE("Failed reading wait_for_fb_sleep, exiting earlysuspend thread\n");
diff --git a/libsync/Android.mk b/libsync/Android.mk
index 626b762..fd1c88c 100644
--- a/libsync/Android.mk
+++ b/libsync/Android.mk
@@ -7,6 +7,7 @@
 LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Werror
 include $(BUILD_SHARED_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -15,4 +16,5 @@
 LOCAL_MODULE_TAGS := optional tests
 LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Werror
 include $(BUILD_EXECUTABLE)
diff --git a/libsysutils/Android.mk b/libsysutils/Android.mk
index 1451b0d..246f954 100644
--- a/libsysutils/Android.mk
+++ b/libsysutils/Android.mk
@@ -18,7 +18,7 @@
 
 LOCAL_C_INCLUDES :=
 
-LOCAL_CFLAGS :=
+LOCAL_CFLAGS := -Werror
 
 LOCAL_SHARED_LIBRARIES := libcutils liblog
 
diff --git a/libsysutils/EventLogTags.logtags b/libsysutils/EventLogTags.logtags
index 7aa5cad..713f8cd 100644
--- a/libsysutils/EventLogTags.logtags
+++ b/libsysutils/EventLogTags.logtags
@@ -1,5 +1,5 @@
 # See system/core/logcat/event.logtags for a description of the format of this file.
 
 # FrameworkListener dispatchCommand overflow
-78001 dispatchCommand_overflow
-65537 netlink_failure (uid|1)
+78001 exp_det_dispatchCommand_overflow
+65537 exp_det_netlink_failure (uid|1)
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index a5ffda2..e7b3dd6 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -39,6 +39,11 @@
     init(socketName, false);
 }
 
+FrameworkListener::FrameworkListener(int sock) :
+                            SocketListener(sock, true) {
+    init(NULL, false);
+}
+
 void FrameworkListener::init(const char *socketName UNUSED, bool withSeq) {
     mCommands = new FrameworkCommandCollection();
     errorRate = 0;
@@ -87,7 +92,6 @@
     char *qlimit = tmp + sizeof(tmp) - 1;
     bool esc = false;
     bool quote = false;
-    int k;
     bool haveCmdNum = !mWithSeq;
 
     memset(argv, 0, sizeof(argv));
@@ -161,7 +165,7 @@
         goto overflow;
     argv[argc++] = strdup(tmp);
 #if 0
-    for (k = 0; k < argc; k++) {
+    for (int k = 0; k < argc; k++) {
         SLOGD("arg[%d] = '%s'", k, argv[k]);
     }
 #endif
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 34f2016..1c9c70a 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -109,7 +109,7 @@
             if (ifaddr->ifa_family == AF_INET) {
                 struct in_addr *addr4 = (struct in_addr *) RTA_DATA(rta);
                 if (RTA_PAYLOAD(rta) < sizeof(*addr4)) {
-                    SLOGE("Short IPv4 address (%d bytes) in %s",
+                    SLOGE("Short IPv4 address (%zu bytes) in %s",
                           RTA_PAYLOAD(rta), msgtype);
                     continue;
                 }
@@ -117,7 +117,7 @@
             } else if (ifaddr->ifa_family == AF_INET6) {
                 struct in6_addr *addr6 = (struct in6_addr *) RTA_DATA(rta);
                 if (RTA_PAYLOAD(rta) < sizeof(*addr6)) {
-                    SLOGE("Short IPv6 address (%d bytes) in %s",
+                    SLOGE("Short IPv6 address (%zu bytes) in %s",
                           RTA_PAYLOAD(rta), msgtype);
                     continue;
                 }
@@ -152,7 +152,7 @@
             }
 
             if (RTA_PAYLOAD(rta) < sizeof(*cacheinfo)) {
-                SLOGE("Short IFA_CACHEINFO (%d vs. %d bytes) in %s",
+                SLOGE("Short IFA_CACHEINFO (%zu vs. %zu bytes) in %s",
                       RTA_PAYLOAD(rta), sizeof(cacheinfo), msgtype);
                 continue;
             }
@@ -174,7 +174,6 @@
 }
 
 /*
-<<<<<<< HEAD
  * Parse a RTM_NEWNDUSEROPT message.
  */
 bool NetlinkEvent::parseNdUserOptMessage(struct nduseroptmsg *msg, int len) {
@@ -399,7 +398,6 @@
     const char *s = buffer;
     const char *end;
     int param_idx = 0;
-    int i;
     int first = 1;
 
     if (size == 0)
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
index 3625d93..d3ce8f5 100644
--- a/libsysutils/src/SocketClient.cpp
+++ b/libsysutils/src/SocketClient.cpp
@@ -1,10 +1,11 @@
 #include <alloca.h>
 #include <errno.h>
-#include <sys/socket.h>
-#include <sys/types.h>
 #include <pthread.h>
+#include <signal.h>
 #include <string.h>
 #include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/types.h>
 
 #define LOG_TAG "SocketClient"
 #include <cutils/log.h>
@@ -43,8 +44,7 @@
     }
 }
 
-SocketClient::~SocketClient()
-{
+SocketClient::~SocketClient() {
     if (mSocketOwned) {
         close(mSocket);
     }
@@ -180,10 +180,19 @@
         return 0;
     }
 
+    int ret = 0;
+    int e = 0; // SLOGW and sigaction are not inert regarding errno
     int current = 0;
 
+    struct sigaction new_action, old_action;
+    memset(&new_action, 0, sizeof(new_action));
+    new_action.sa_handler = SIG_IGN;
+    sigaction(SIGPIPE, &new_action, &old_action);
+
     for (;;) {
-        ssize_t rc = writev(mSocket, iov + current, iovcnt - current);
+        ssize_t rc = TEMP_FAILURE_RETRY(
+            writev(mSocket, iov + current, iovcnt - current));
+
         if (rc > 0) {
             size_t written = rc;
             while ((current < iovcnt) && (written >= iov[current].iov_len)) {
@@ -198,18 +207,21 @@
             continue;
         }
 
-        if (rc < 0 && errno == EINTR)
-            continue;
-
         if (rc == 0) {
+            e = EIO;
             SLOGW("0 length write :(");
-            errno = EIO;
         } else {
-            SLOGW("write error (%s)", strerror(errno));
+            e = errno;
+            SLOGW("write error (%s)", strerror(e));
         }
-        return -1;
+        ret = -1;
+        break;
     }
-    return 0;
+
+    sigaction(SIGPIPE, &old_action, &new_action);
+
+    errno = e;
+    return ret;
 }
 
 void SocketClient::incRef() {
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 5c75206..527a6a0 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -70,6 +70,10 @@
 }
 
 int SocketListener::startListener() {
+    return startListener(4);
+}
+
+int SocketListener::startListener(int backlog) {
 
     if (!mSocketName && mSock == -1) {
         SLOGE("Failed to start unbound listener");
@@ -84,7 +88,7 @@
         SLOGV("got mSock = %d for %s", mSock, mSocketName);
     }
 
-    if (mListen && listen(mSock, 4) < 0) {
+    if (mListen && listen(mSock, backlog) < 0) {
         SLOGE("Unable to listen on socket (%s)", strerror(errno));
         return -1;
     } else if (!mListen)
diff --git a/libusbhost/Android.mk b/libusbhost/Android.mk
index 9565cc5..5c12f2c 100644
--- a/libusbhost/Android.mk
+++ b/libusbhost/Android.mk
@@ -14,7 +14,7 @@
 # limitations under the License.
 #
 
-LOCAL_PATH := $(my-dir)
+LOCAL_PATH := $(call my-dir)
 
 # Static library for Linux host
 # ========================================================
@@ -25,6 +25,7 @@
 
 LOCAL_MODULE := libusbhost
 LOCAL_SRC_FILES := usbhost.c
+LOCAL_CFLAGS := -Werror
 
 include $(BUILD_HOST_STATIC_LIBRARY)
 
@@ -38,7 +39,7 @@
 LOCAL_MODULE := libusbhost
 LOCAL_SRC_FILES := usbhost.c
 
-LOCAL_CFLAGS := -g -DUSE_LIBLOG
+LOCAL_CFLAGS := -g -DUSE_LIBLOG -Werror
 
 # needed for logcat
 LOCAL_SHARED_LIBRARIES := libcutils
@@ -52,5 +53,6 @@
 
 LOCAL_MODULE := libusbhost
 LOCAL_SRC_FILES := usbhost.c
+LOCAL_CFLAGS := -Werror
 
 include $(BUILD_STATIC_LIBRARY)
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index 8be393e..cd8000a 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -263,11 +263,12 @@
                 D("%s subdirectory %s: index: %d\n", (event->mask & IN_CREATE) ?
                         "new" : "gone", path, i);
                 if (i > 0 && i < MAX_USBFS_WD_COUNT) {
+                    int local_ret = 0;
                     if (event->mask & IN_CREATE) {
-                        ret = inotify_add_watch(context->fd, path,
+                        local_ret = inotify_add_watch(context->fd, path,
                                 IN_CREATE | IN_DELETE);
-                        if (ret >= 0)
-                            context->wds[i] = ret;
+                        if (local_ret >= 0)
+                            context->wds[i] = local_ret;
                         done = find_existing_devices_bus(path, context->cb_added,
                                 context->data);
                     } else if (event->mask & IN_DELETE) {
diff --git a/libutils/Android.mk b/libutils/Android.mk
index 1710d36..9a50147 100644
--- a/libutils/Android.mk
+++ b/libutils/Android.mk
@@ -43,7 +43,7 @@
 	VectorImpl.cpp \
 	misc.cpp
 
-host_commonCflags := -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS)
+host_commonCflags := -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS) -Werror
 
 ifeq ($(HOST_OS),windows)
 ifeq ($(strip $(USE_CYGWIN),),)
@@ -69,7 +69,7 @@
 LOCAL_MODULE:= libutils
 LOCAL_STATIC_LIBRARIES := liblog
 LOCAL_CFLAGS += $(host_commonCflags)
-LOCAL_LDLIBS += $(host_commonLdlibs)
+LOCAL_MULTILIB := both
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 
@@ -83,7 +83,6 @@
 LOCAL_MODULE:= lib64utils
 LOCAL_STATIC_LIBRARIES := liblog
 LOCAL_CFLAGS += $(host_commonCflags) -m64
-LOCAL_LDLIBS += $(host_commonLdlibs)
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 
@@ -98,20 +97,15 @@
 	Looper.cpp \
 	Trace.cpp
 
-ifeq ($(TARGET_OS),linux)
-LOCAL_LDLIBS += -lrt -ldl
-endif
-
 ifeq ($(TARGET_ARCH),mips)
 LOCAL_CFLAGS += -DALIGN_DOUBLE
 endif
+LOCAL_CFLAGS += -Werror
 
 LOCAL_C_INCLUDES += \
 		bionic/libc/private \
 		external/zlib
 
-LOCAL_LDLIBS += -lpthread
-
 LOCAL_STATIC_LIBRARIES := \
 	libcutils
 
@@ -134,7 +128,8 @@
         libbacktrace \
         libcutils \
         libdl \
-        liblog \
+        liblog
+LOCAL_CFLAGS := -Werror
 
 include external/stlport/libstlport.mk
 
diff --git a/libutils/BlobCache.cpp b/libutils/BlobCache.cpp
index 0fb1d8e..f00bf14 100644
--- a/libutils/BlobCache.cpp
+++ b/libutils/BlobCache.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "BlobCache"
 //#define LOG_NDEBUG 0
 
+#include <inttypes.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -27,7 +28,7 @@
 namespace android {
 
 // BlobCache::Header::mMagicNumber value
-static const uint32_t blobCacheMagic = '_Bb$';
+static const uint32_t blobCacheMagic = ('_' << 24) + ('B' << 16) + ('b' << 8) + '$';
 
 // BlobCache::Header::mBlobCacheVersion value
 static const uint32_t blobCacheVersion = 1;
@@ -48,24 +49,24 @@
     mRandState[1] = (now >> 16) & 0xFFFF;
     mRandState[2] = (now >> 32) & 0xFFFF;
 #endif
-    ALOGV("initializing random seed using %lld", now);
+    ALOGV("initializing random seed using %lld", (unsigned long long)now);
 }
 
 void BlobCache::set(const void* key, size_t keySize, const void* value,
         size_t valueSize) {
     if (mMaxKeySize < keySize) {
-        ALOGV("set: not caching because the key is too large: %d (limit: %d)",
+        ALOGV("set: not caching because the key is too large: %zu (limit: %zu)",
                 keySize, mMaxKeySize);
         return;
     }
     if (mMaxValueSize < valueSize) {
-        ALOGV("set: not caching because the value is too large: %d (limit: %d)",
+        ALOGV("set: not caching because the value is too large: %zu (limit: %zu)",
                 valueSize, mMaxValueSize);
         return;
     }
     if (mMaxTotalSize < keySize + valueSize) {
         ALOGV("set: not caching because the combined key/value size is too "
-                "large: %d (limit: %d)", keySize + valueSize, mMaxTotalSize);
+                "large: %zu (limit: %zu)", keySize + valueSize, mMaxTotalSize);
         return;
     }
     if (keySize == 0) {
@@ -94,15 +95,15 @@
                     continue;
                 } else {
                     ALOGV("set: not caching new key/value pair because the "
-                            "total cache size limit would be exceeded: %d "
-                            "(limit: %d)",
+                            "total cache size limit would be exceeded: %zu "
+                            "(limit: %zu)",
                             keySize + valueSize, mMaxTotalSize);
                     break;
                 }
             }
             mCacheEntries.add(CacheEntry(keyBlob, valueBlob));
             mTotalSize = newTotalSize;
-            ALOGV("set: created new cache entry with %d byte key and %d byte value",
+            ALOGV("set: created new cache entry with %zu byte key and %zu byte value",
                     keySize, valueSize);
         } else {
             // Update the existing cache entry.
@@ -116,14 +117,14 @@
                     continue;
                 } else {
                     ALOGV("set: not caching new value because the total cache "
-                            "size limit would be exceeded: %d (limit: %d)",
+                            "size limit would be exceeded: %zu (limit: %zu)",
                             keySize + valueSize, mMaxTotalSize);
                     break;
                 }
             }
             mCacheEntries.editItemAt(index).setValue(valueBlob);
             mTotalSize = newTotalSize;
-            ALOGV("set: updated existing cache entry with %d byte key and %d byte "
+            ALOGV("set: updated existing cache entry with %zu byte key and %zu byte "
                     "value", keySize, valueSize);
         }
         break;
@@ -133,7 +134,7 @@
 size_t BlobCache::get(const void* key, size_t keySize, void* value,
         size_t valueSize) {
     if (mMaxKeySize < keySize) {
-        ALOGV("get: not searching because the key is too large: %d (limit %d)",
+        ALOGV("get: not searching because the key is too large: %zu (limit %zu)",
                 keySize, mMaxKeySize);
         return 0;
     }
@@ -141,7 +142,7 @@
     CacheEntry dummyEntry(dummyKey, NULL);
     ssize_t index = mCacheEntries.indexOf(dummyEntry);
     if (index < 0) {
-        ALOGV("get: no cache entry found for key of size %d", keySize);
+        ALOGV("get: no cache entry found for key of size %zu", keySize);
         return 0;
     }
 
@@ -150,10 +151,10 @@
     sp<Blob> valueBlob(mCacheEntries[index].getValue());
     size_t valueBlobSize = valueBlob->getSize();
     if (valueBlobSize <= valueSize) {
-        ALOGV("get: copying %d bytes to caller's buffer", valueBlobSize);
+        ALOGV("get: copying %zu bytes to caller's buffer", valueBlobSize);
         memcpy(value, valueBlob->getData(), valueBlobSize);
     } else {
-        ALOGV("get: caller's buffer is too small for value: %d (needs %d)",
+        ALOGV("get: caller's buffer is too small for value: %zu (needs %zu)",
                 valueSize, valueBlobSize);
     }
     return valueBlobSize;
@@ -229,7 +230,7 @@
     }
     const Header* header = reinterpret_cast<const Header*>(buffer);
     if (header->mMagicNumber != blobCacheMagic) {
-        ALOGE("unflatten: bad magic number: %d", header->mMagicNumber);
+        ALOGE("unflatten: bad magic number: %" PRIu32, header->mMagicNumber);
         return BAD_VALUE;
     }
     if (header->mBlobCacheVersion != blobCacheVersion ||
diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp
index 9ce370e..be4b14f 100644
--- a/libutils/FileMap.cpp
+++ b/libutils/FileMap.cpp
@@ -23,6 +23,13 @@
 #include <utils/FileMap.h>
 #include <utils/Log.h>
 
+#if defined(HAVE_WIN32_FILEMAP) && !defined(__USE_MINGW_ANSI_STDIO)
+# define PRId32 "I32d"
+# define PRIx32 "I32x"
+# define PRId64 "I64d"
+#else
+#include <inttypes.h>
+#endif
 #include <stdio.h>
 #include <stdlib.h>
 
@@ -39,37 +46,32 @@
 
 /*static*/ long FileMap::mPageSize = -1;
 
-
-/*
- * Constructor.  Create an empty object.
- */
+// Constructor.  Create an empty object.
 FileMap::FileMap(void)
     : mRefCount(1), mFileName(NULL), mBasePtr(NULL), mBaseLength(0),
       mDataPtr(NULL), mDataLength(0)
 {
 }
 
-/*
- * Destructor.
- */
+// Destructor.
 FileMap::~FileMap(void)
 {
     assert(mRefCount == 0);
 
-    //printf("+++ removing FileMap %p %u\n", mDataPtr, mDataLength);
+    //printf("+++ removing FileMap %p %zu\n", mDataPtr, mDataLength);
 
     mRefCount = -100;       // help catch double-free
     if (mFileName != NULL) {
         free(mFileName);
     }
-#ifdef HAVE_POSIX_FILEMAP    
+#ifdef HAVE_POSIX_FILEMAP
     if (mBasePtr && munmap(mBasePtr, mBaseLength) != 0) {
-        ALOGD("munmap(%p, %d) failed\n", mBasePtr, (int) mBaseLength);
+        ALOGD("munmap(%p, %zu) failed\n", mBasePtr, mBaseLength);
     }
 #endif
 #ifdef HAVE_WIN32_FILEMAP
     if (mBasePtr && UnmapViewOfFile(mBasePtr) == 0) {
-        ALOGD("UnmapViewOfFile(%p) failed, error = %ld\n", mBasePtr,
+        ALOGD("UnmapViewOfFile(%p) failed, error = %" PRId32 "\n", mBasePtr,
               GetLastError() );
     }
     if (mFileMapping != INVALID_HANDLE_VALUE) {
@@ -80,14 +82,12 @@
 }
 
 
-/*
- * Create a new mapping on an open file.
- *
- * Closing the file descriptor does not unmap the pages, so we don't
- * claim ownership of the fd.
- *
- * Returns "false" on failure.
- */
+// Create a new mapping on an open file.
+//
+// Closing the file descriptor does not unmap the pages, so we don't
+// claim ownership of the fd.
+//
+// Returns "false" on failure.
 bool FileMap::create(const char* origFileName, int fd, off64_t offset, size_t length,
         bool readOnly)
 {
@@ -98,32 +98,32 @@
 
     if (mPageSize == -1) {
         SYSTEM_INFO  si;
-        
+
         GetSystemInfo( &si );
         mPageSize = si.dwAllocationGranularity;
     }
 
     DWORD  protect = readOnly ? PAGE_READONLY : PAGE_READWRITE;
-    
+
     mFileHandle  = (HANDLE) _get_osfhandle(fd);
     mFileMapping = CreateFileMapping( mFileHandle, NULL, protect, 0, 0, NULL);
     if (mFileMapping == NULL) {
-        ALOGE("CreateFileMapping(%p, %lx) failed with error %ld\n",
+        ALOGE("CreateFileMapping(%p, %" PRIx32 ") failed with error %" PRId32 "\n",
               mFileHandle, protect, GetLastError() );
         return false;
     }
-    
+
     adjust    = offset % mPageSize;
     adjOffset = offset - adjust;
     adjLength = length + adjust;
-    
-    mBasePtr = MapViewOfFile( mFileMapping, 
+
+    mBasePtr = MapViewOfFile( mFileMapping,
                               readOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS,
                               0,
                               (DWORD)(adjOffset),
                               adjLength );
     if (mBasePtr == NULL) {
-        ALOGE("MapViewOfFile(%ld, %ld) failed with error %ld\n",
+        ALOGE("MapViewOfFile(%" PRId64 ", %zu) failed with error %" PRId32 "\n",
               adjOffset, adjLength, GetLastError() );
         CloseHandle(mFileMapping);
         mFileMapping = INVALID_HANDLE_VALUE;
@@ -142,7 +142,7 @@
     assert(offset >= 0);
     assert(length > 0);
 
-    /* init on first use */
+    // init on first use
     if (mPageSize == -1) {
 #if NOT_USING_KLIBC
         mPageSize = sysconf(_SC_PAGESIZE);
@@ -151,7 +151,7 @@
             return false;
         }
 #else
-        /* this holds for Linux, Darwin, Cygwin, and doesn't pain the ARM */
+        // this holds for Linux, Darwin, Cygwin, and doesn't pain the ARM
         mPageSize = 4096;
 #endif
     }
@@ -168,19 +168,19 @@
 
     ptr = mmap(NULL, adjLength, prot, flags, fd, adjOffset);
     if (ptr == MAP_FAILED) {
-    	// Cygwin does not seem to like file mapping files from an offset.
-    	// So if we fail, try again with offset zero
-    	if (adjOffset > 0) {
-    		adjust = offset;
-    		goto try_again;
-    	}
-    
-        ALOGE("mmap(%ld,%ld) failed: %s\n",
-            (long) adjOffset, (long) adjLength, strerror(errno));
+        // Cygwin does not seem to like file mapping files from an offset.
+        // So if we fail, try again with offset zero
+        if (adjOffset > 0) {
+            adjust = offset;
+            goto try_again;
+        }
+
+        ALOGE("mmap(%lld,%zu) failed: %s\n",
+            (long long)adjOffset, adjLength, strerror(errno));
         return false;
     }
     mBasePtr = ptr;
-#endif /* HAVE_POSIX_FILEMAP */
+#endif // HAVE_POSIX_FILEMAP
 
     mFileName = origFileName != NULL ? strdup(origFileName) : NULL;
     mBaseLength = adjLength;
@@ -190,15 +190,13 @@
 
     assert(mBasePtr != NULL);
 
-    ALOGV("MAP: base %p/%d data %p/%d\n",
-        mBasePtr, (int) mBaseLength, mDataPtr, (int) mDataLength);
+    ALOGV("MAP: base %p/%zu data %p/%zu\n",
+        mBasePtr, mBaseLength, mDataPtr, mDataLength);
 
     return true;
 }
 
-/*
- * Provide guidance to the system.
- */
+// Provide guidance to the system.
 int FileMap::advise(MapAdvice advice)
 {
 #if HAVE_MADVISE
@@ -220,6 +218,6 @@
         ALOGW("madvise(%d) failed: %s\n", sysAdvice, strerror(errno));
     return cc;
 #else
-	return -1;
+    return -1;
 #endif // HAVE_MADVISE
 }
diff --git a/libutils/LinearAllocator.cpp b/libutils/LinearAllocator.cpp
index a07a291..8b90696 100644
--- a/libutils/LinearAllocator.cpp
+++ b/libutils/LinearAllocator.cpp
@@ -92,7 +92,7 @@
         : mNextPage(0)
     {}
 
-    void* operator new(size_t size, void* buf) { return buf; }
+    void* operator new(size_t /*size*/, void* buf) { return buf; }
 
     void* start() {
         return (void*) (((size_t)this) + sizeof(Page));
@@ -103,7 +103,7 @@
     }
 
 private:
-    Page(const Page& other) {}
+    Page(const Page& /*other*/) {}
     Page* mNextPage;
 };
 
diff --git a/libutils/Printer.cpp b/libutils/Printer.cpp
index 263e740..1dc8632 100644
--- a/libutils/Printer.cpp
+++ b/libutils/Printer.cpp
@@ -25,10 +25,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-#ifndef __BIONIC__
-#define fdprintf dprintf
-#endif
-
 namespace android {
 
 /*
@@ -120,7 +116,7 @@
     }
 
 #ifndef USE_MINGW
-    fdprintf(mFd, mFormatString, mPrefix, string);
+    dprintf(mFd, mFormatString, mPrefix, string);
 #endif
 }
 
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index f398a82..02907ad 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -17,6 +17,14 @@
 #define LOG_TAG "RefBase"
 // #define LOG_NDEBUG 0
 
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <typeinfo>
+#include <unistd.h>
+
 #include <utils/RefBase.h>
 
 #include <utils/Atomic.h>
@@ -24,13 +32,9 @@
 #include <utils/Log.h>
 #include <utils/threads.h>
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <typeinfo>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
 
 // compile with refcounting debugging enabled
 #define DEBUG_REFS                      0
@@ -109,7 +113,7 @@
                 char inc = refs->ref >= 0 ? '+' : '-';
                 ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
 #if DEBUG_REFS_CALLSTACK_ENABLED
-                refs->stack.dump(LOG_TAG);
+                refs->stack.log(LOG_TAG);
 #endif
                 refs = refs->next;
             }
@@ -123,7 +127,7 @@
                 char inc = refs->ref >= 0 ? '+' : '-';
                 ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
 #if DEBUG_REFS_CALLSTACK_ENABLED
-                refs->stack.dump(LOG_TAG);
+                refs->stack.log(LOG_TAG);
 #endif
                 refs = refs->next;
             }
@@ -388,7 +392,7 @@
 {
     weakref_impl* const impl = static_cast<weakref_impl*>(this);
     impl->addWeakRef(id);
-    const int32_t c = android_atomic_inc(&impl->mWeak);
+    const int32_t c __unused = android_atomic_inc(&impl->mWeak);
     ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
 }
 
@@ -615,7 +619,7 @@
 {
 }
 
-bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)
+bool RefBase::onIncStrongAttempted(uint32_t flags, const void* /*id*/)
 {
     return (flags&FIRST_INC_STRONG) ? true : false;
 }
@@ -626,13 +630,15 @@
 
 // ---------------------------------------------------------------------------
 
-void RefBase::renameRefs(size_t n, const ReferenceRenamer& renamer) {
 #if DEBUG_REFS
+void RefBase::renameRefs(size_t n, const ReferenceRenamer& renamer) {
     for (size_t i=0 ; i<n ; i++) {
         renamer(i);
     }
-#endif
 }
+#else
+void RefBase::renameRefs(size_t /*n*/, const ReferenceRenamer& /*renamer*/) { }
+#endif
 
 void RefBase::renameRefId(weakref_type* ref,
         const void* old_id, const void* new_id) {
diff --git a/libutils/StopWatch.cpp b/libutils/StopWatch.cpp
index b1708d6..8c7b596 100644
--- a/libutils/StopWatch.cpp
+++ b/libutils/StopWatch.cpp
@@ -21,7 +21,9 @@
 #include <stdio.h>
 
 /* for PRId64 */
+#ifndef __STDC_FORMAT_MACROS
 #define __STDC_FORMAT_MACROS 1
+#endif
 #include <inttypes.h>
 
 #include <utils/Log.h>
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index b09b728..91efdaa 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -16,7 +16,6 @@
 
 #include <utils/String16.h>
 
-#include <utils/Debug.h>
 #include <utils/Log.h>
 #include <utils/Unicode.h>
 #include <utils/String8.h>
@@ -67,8 +66,6 @@
         return getEmptyString();
     }
 
-    const uint8_t* const u8end = u8cur + u8len;
-
     SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t)*(u16len+1));
     if (buf) {
         u8cur = (const uint8_t*) u8str;
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index e852d77..49340bb 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -323,8 +323,17 @@
 
 status_t String8::appendFormatV(const char* fmt, va_list args)
 {
-    int result = NO_ERROR;
-    int n = vsnprintf(NULL, 0, fmt, args);
+    int n, result = NO_ERROR;
+    va_list tmp_args;
+
+    /* args is undefined after vsnprintf.
+     * So we need a copy here to avoid the
+     * second vsnprintf access undefined args.
+     */
+    va_copy(tmp_args, args);
+    n = vsnprintf(NULL, 0, fmt, tmp_args);
+    va_end(tmp_args);
+
     if (n != 0) {
         size_t oldLength = length();
         char* buf = lockBuffer(oldLength + n);
@@ -542,7 +551,6 @@
 {
     const char* lastSlash;
     const char* lastDot;
-    int extLen;
     const char* const str = mString;
 
     // only look at the filename
diff --git a/libutils/SystemClock.cpp b/libutils/SystemClock.cpp
index 413250f..dbad581 100644
--- a/libutils/SystemClock.cpp
+++ b/libutils/SystemClock.cpp
@@ -68,13 +68,7 @@
  */
 #define DEBUG_TIMESTAMP         0
 
-static const char *gettime_method_names[] = {
-    "clock_gettime",
-    "ioctl",
-    "systemTime",
-};
-
-#if DEBUG_TIMESTAMP
+#if DEBUG_TIMESTAMP && defined(ARCH_ARM)
 static inline void checkTimeStamps(int64_t timestamp,
                                    int64_t volatile *prevTimestampPtr,
                                    int volatile *prevMethodPtr,
@@ -85,11 +79,16 @@
      * gettid, and int64_t is different on the ARM platform
      * (ie long vs long long).
      */
-#ifdef ARCH_ARM
     int64_t prevTimestamp = *prevTimestampPtr;
     int prevMethod = *prevMethodPtr;
 
     if (timestamp < prevTimestamp) {
+        static const char *gettime_method_names[] = {
+            "clock_gettime",
+            "ioctl",
+            "systemTime",
+        };
+
         ALOGW("time going backwards: prev %lld(%s) vs now %lld(%s), tid=%d",
               prevTimestamp, gettime_method_names[prevMethod],
               timestamp, gettime_method_names[curMethod],
@@ -99,7 +98,6 @@
     // write is interrupted or not observed as a whole.
     *prevTimestampPtr = timestamp;
     *prevMethodPtr = curMethod;
-#endif
 }
 #else
 #define checkTimeStamps(timestamp, prevTimestampPtr, prevMethodPtr, curMethod)
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index ff74914..cc7fe89 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -17,16 +17,11 @@
 // #define LOG_NDEBUG 0
 #define LOG_TAG "libutils.threads"
 
-#include <utils/threads.h>
-#include <utils/Log.h>
-
-#include <cutils/sched_policy.h>
-
+#include <assert.h>
+#include <errno.h>
+#include <memory.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <memory.h>
-#include <errno.h>
-#include <assert.h>
 #include <unistd.h>
 
 #if defined(HAVE_PTHREADS)
@@ -47,6 +42,17 @@
 #include <sys/prctl.h>
 #endif
 
+#include <utils/threads.h>
+#include <utils/Log.h>
+
+#include <cutils/sched_policy.h>
+
+#ifdef HAVE_ANDROID_OS
+# define __android_unused
+#else
+# define __android_unused __attribute__((__unused__))
+#endif
+
 /*
  * ===========================================================================
  *      Thread wrappers
@@ -119,7 +125,7 @@
 
 int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
                                void *userData,
-                               const char* threadName,
+                               const char* threadName __android_unused,
                                int32_t threadPriority,
                                size_t threadStackSize,
                                android_thread_id_t *threadId)
@@ -251,9 +257,9 @@
 
 int androidCreateRawThreadEtc(android_thread_func_t fn,
                                void *userData,
-                               const char* threadName,
-                               int32_t threadPriority,
-                               size_t threadStackSize,
+                               const char* /*threadName*/,
+                               int32_t /*threadPriority*/,
+                               size_t /*threadStackSize*/,
                                android_thread_id_t *threadId)
 {
     return doCreateThread(  fn, userData, threadId);
diff --git a/libutils/Timers.cpp b/libutils/Timers.cpp
index 5293cd2..4687d4d 100644
--- a/libutils/Timers.cpp
+++ b/libutils/Timers.cpp
@@ -32,9 +32,9 @@
 #include <windows.h>
 #endif
 
+#if defined(HAVE_ANDROID_OS)
 nsecs_t systemTime(int clock)
 {
-#if defined(HAVE_POSIX_CLOCKS)
     static const clockid_t clocks[] = {
             CLOCK_REALTIME,
             CLOCK_MONOTONIC,
@@ -46,14 +46,19 @@
     t.tv_sec = t.tv_nsec = 0;
     clock_gettime(clocks[clock], &t);
     return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec;
+}
 #else
-    // we don't support the clocks here.
+nsecs_t systemTime(int /*clock*/)
+{
+    // Clock support varies widely across hosts. Mac OS doesn't support
+    // posix clocks, older glibcs don't support CLOCK_BOOTTIME and Windows
+    // is windows.
     struct timeval t;
     t.tv_sec = t.tv_usec = 0;
     gettimeofday(&t, NULL);
     return nsecs_t(t.tv_sec)*1000000000LL + nsecs_t(t.tv_usec)*1000LL;
-#endif
 }
+#endif
 
 int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime)
 {
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index a66e3bb..fe8887d 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -576,7 +576,7 @@
 char16_t* utf8_to_utf16_n(const uint8_t* src, size_t srcLen, char16_t* dst, size_t dstLen) {
     const uint8_t* const u8end = src + srcLen;
     const uint8_t* u8cur = src;
-    const uint16_t* const u16end = dst + dstLen;
+    const char16_t* const u16end = dst + dstLen;
     char16_t* u16cur = dst;
 
     while (u8cur < u8end && u16cur < u16end) {
diff --git a/libutils/tests/BasicHashtable_test.cpp b/libutils/tests/BasicHashtable_test.cpp
index 7dcf750..a61b1e1 100644
--- a/libutils/tests/BasicHashtable_test.cpp
+++ b/libutils/tests/BasicHashtable_test.cpp
@@ -397,7 +397,7 @@
         const SimpleEntry& entry = h.entryAt(index);
         ASSERT_GE(entry.key, 0);
         ASSERT_LT(entry.key, N);
-        ASSERT_EQ(false, set[entry.key]);
+        ASSERT_FALSE(set[entry.key]);
         ASSERT_EQ(entry.key * 10, entry.value);
 
         set[entry.key] = true;
diff --git a/libutils/tests/BlobCache_test.cpp b/libutils/tests/BlobCache_test.cpp
index 7202123..dac4e2c 100644
--- a/libutils/tests/BlobCache_test.cpp
+++ b/libutils/tests/BlobCache_test.cpp
@@ -44,7 +44,7 @@
 };
 
 TEST_F(BlobCacheTest, CacheSingleValueSucceeds) {
-    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
     mBC->set("abcd", 4, "efgh", 4);
     ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
     ASSERT_EQ('e', buf[0]);
@@ -54,7 +54,7 @@
 }
 
 TEST_F(BlobCacheTest, CacheTwoValuesSucceeds) {
-    char buf[2] = { 0xee, 0xee };
+    unsigned char buf[2] = { 0xee, 0xee };
     mBC->set("ab", 2, "cd", 2);
     mBC->set("ef", 2, "gh", 2);
     ASSERT_EQ(size_t(2), mBC->get("ab", 2, buf, 2));
@@ -66,7 +66,7 @@
 }
 
 TEST_F(BlobCacheTest, GetOnlyWritesInsideBounds) {
-    char buf[6] = { 0xee, 0xee, 0xee, 0xee, 0xee, 0xee };
+    unsigned char buf[6] = { 0xee, 0xee, 0xee, 0xee, 0xee, 0xee };
     mBC->set("abcd", 4, "efgh", 4);
     ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf+1, 4));
     ASSERT_EQ(0xee, buf[0]);
@@ -78,7 +78,7 @@
 }
 
 TEST_F(BlobCacheTest, GetOnlyWritesIfBufferIsLargeEnough) {
-    char buf[3] = { 0xee, 0xee, 0xee };
+    unsigned char buf[3] = { 0xee, 0xee, 0xee };
     mBC->set("abcd", 4, "efgh", 4);
     ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 3));
     ASSERT_EQ(0xee, buf[0]);
@@ -92,7 +92,7 @@
 }
 
 TEST_F(BlobCacheTest, MultipleSetsCacheLatestValue) {
-    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
     mBC->set("abcd", 4, "efgh", 4);
     mBC->set("abcd", 4, "ijkl", 4);
     ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
@@ -103,7 +103,7 @@
 }
 
 TEST_F(BlobCacheTest, SecondSetKeepsFirstValueIfTooLarge) {
-    char buf[MAX_VALUE_SIZE+1] = { 0xee, 0xee, 0xee, 0xee };
+    unsigned char buf[MAX_VALUE_SIZE+1] = { 0xee, 0xee, 0xee, 0xee };
     mBC->set("abcd", 4, "efgh", 4);
     mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1);
     ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
@@ -115,7 +115,7 @@
 
 TEST_F(BlobCacheTest, DoesntCacheIfKeyIsTooBig) {
     char key[MAX_KEY_SIZE+1];
-    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
     for (int i = 0; i < MAX_KEY_SIZE+1; i++) {
         key[i] = 'a';
     }
@@ -165,7 +165,7 @@
 
 TEST_F(BlobCacheTest, CacheMaxKeySizeSucceeds) {
     char key[MAX_KEY_SIZE];
-    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
     for (int i = 0; i < MAX_KEY_SIZE; i++) {
         key[i] = 'a';
     }
@@ -214,7 +214,7 @@
 }
 
 TEST_F(BlobCacheTest, CacheMinKeyAndValueSizeSucceeds) {
-    char buf[1] = { 0xee };
+    unsigned char buf[1] = { 0xee };
     mBC->set("x", 1, "y", 1);
     ASSERT_EQ(size_t(1), mBC->get("x", 1, buf, 1));
     ASSERT_EQ('y', buf[0]);
@@ -282,7 +282,7 @@
 };
 
 TEST_F(BlobCacheFlattenTest, FlattenOneValue) {
-    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
     mBC->set("abcd", 4, "efgh", 4);
     roundTrip();
     ASSERT_EQ(size_t(4), mBC2->get("abcd", 4, buf, 4));
@@ -348,7 +348,7 @@
 }
 
 TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadMagic) {
-    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
     mBC->set("abcd", 4, "efgh", 4);
 
     size_t size = mBC->getFlattenedSize();
@@ -365,7 +365,7 @@
 }
 
 TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheVersion) {
-    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
     mBC->set("abcd", 4, "efgh", 4);
 
     size_t size = mBC->getFlattenedSize();
@@ -384,7 +384,7 @@
 }
 
 TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheDeviceVersion) {
-    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
     mBC->set("abcd", 4, "efgh", 4);
 
     size_t size = mBC->getFlattenedSize();
@@ -403,7 +403,7 @@
 }
 
 TEST_F(BlobCacheFlattenTest, UnflattenCatchesBufferTooSmall) {
-    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
     mBC->set("abcd", 4, "efgh", 4);
 
     size_t size = mBC->getFlattenedSize();
diff --git a/libutils/tests/LruCache_test.cpp b/libutils/tests/LruCache_test.cpp
index e573952..bcbea32 100644
--- a/libutils/tests/LruCache_test.cpp
+++ b/libutils/tests/LruCache_test.cpp
@@ -184,7 +184,7 @@
 
     for (size_t i = 0; i < kNumKeys; i++) {
         strings[i] = (char *)malloc(16);
-        sprintf(strings[i], "%d", i);
+        sprintf(strings[i], "%zu", i);
     }
 
     srandom(12345);
diff --git a/libziparchive/Android.mk b/libziparchive/Android.mk
index e754c3b..705caa5 100644
--- a/libziparchive/Android.mk
+++ b/libziparchive/Android.mk
@@ -30,6 +30,7 @@
 LOCAL_MODULE:= libziparchive
 
 LOCAL_C_INCLUDES += ${includes}
+LOCAL_CFLAGS := -Werror
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -40,6 +41,8 @@
 
 LOCAL_STATIC_LIBRARIES := libz libutils
 LOCAL_MODULE:= libziparchive-host
+LOCAL_CFLAGS := -Werror
+LOCAL_MULTILIB := both
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -47,7 +50,8 @@
 LOCAL_CPP_EXTENSION := .cc
 LOCAL_CFLAGS += \
     -DGTEST_OS_LINUX_ANDROID \
-    -DGTEST_HAS_STD_STRING
+    -DGTEST_HAS_STD_STRING \
+    -Werror
 LOCAL_SRC_FILES := zip_archive_test.cc
 LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_STATIC_LIBRARIES := libziparchive libz libgtest libgtest_main libutils
@@ -58,7 +62,8 @@
 LOCAL_CPP_EXTENSION := .cc
 LOCAL_CFLAGS += \
     -DGTEST_OS_LINUX \
-    -DGTEST_HAS_STD_STRING
+    -DGTEST_HAS_STD_STRING \
+    -Werror
 LOCAL_SRC_FILES := zip_archive_test.cc
 LOCAL_STATIC_LIBRARIES := libziparchive-host \
 	libz \
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index a23d4ae..128bad4 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -17,73 +17,191 @@
 /*
  * Read-only access to Zip archives, with minimal heap allocation.
  */
-#include "ziparchive/zip_archive.h"
-
-#include <zlib.h>
 
 #include <assert.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
 #include <limits.h>
 #include <log/log.h>
-#include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <utils/Compat.h>
 #include <utils/FileMap.h>
+#include <zlib.h>
 
 #include <JNIHelp.h>  // TEMP_FAILURE_RETRY may or may not be in unistd
 
-// This is for windows. If we don't open a file in binary mode, weirds
+#include "ziparchive/zip_archive.h"
+
+// This is for windows. If we don't open a file in binary mode, weird
 // things will happen.
 #ifndef O_BINARY
 #define O_BINARY 0
 #endif
 
-/*
- * Zip file constants.
- */
-static const uint32_t kEOCDSignature    = 0x06054b50;
-static const uint32_t kEOCDLen          = 2;
-static const uint32_t kEOCDNumEntries   = 8;              // offset to #of entries in file
-static const uint32_t kEOCDSize         = 12;             // size of the central directory
-static const uint32_t kEOCDFileOffset   = 16;             // offset to central directory
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+    TypeName(); \
+    TypeName(const TypeName&); \
+    void operator=(const TypeName&)
 
-static const uint32_t kMaxCommentLen    = 65535;          // longest possible in ushort
-static const uint32_t kMaxEOCDSearch    = (kMaxCommentLen + kEOCDLen);
+// The "end of central directory" (EOCD) record. Each archive
+// contains exactly once such record which appears at the end of
+// the archive. It contains archive wide information like the
+// number of entries in the archive and the offset to the central
+// directory of the offset.
+struct EocdRecord {
+  static const uint32_t kSignature = 0x06054b50;
 
-static const uint32_t kLFHSignature     = 0x04034b50;
-static const uint32_t kLFHLen           = 30;             // excluding variable-len fields
-static const uint32_t kLFHGPBFlags      = 6;              // general purpose bit flags
-static const uint32_t kLFHCRC           = 14;             // offset to CRC
-static const uint32_t kLFHCompLen       = 18;             // offset to compressed length
-static const uint32_t kLFHUncompLen     = 22;             // offset to uncompressed length
-static const uint32_t kLFHNameLen       = 26;             // offset to filename length
-static const uint32_t kLFHExtraLen      = 28;             // offset to extra length
+  // End of central directory signature, should always be
+  // |kSignature|.
+  uint32_t eocd_signature;
+  // The number of the current "disk", i.e, the "disk" that this
+  // central directory is on.
+  //
+  // This implementation assumes that each archive spans a single
+  // disk only. i.e, that disk_num == 1.
+  uint16_t disk_num;
+  // The disk where the central directory starts.
+  //
+  // This implementation assumes that each archive spans a single
+  // disk only. i.e, that cd_start_disk == 1.
+  uint16_t cd_start_disk;
+  // The number of central directory records on this disk.
+  //
+  // This implementation assumes that each archive spans a single
+  // disk only. i.e, that num_records_on_disk == num_records.
+  uint16_t num_records_on_disk;
+  // The total number of central directory records.
+  uint16_t num_records;
+  // The size of the central directory (in bytes).
+  uint32_t cd_size;
+  // The offset of the start of the central directory, relative
+  // to the start of the file.
+  uint32_t cd_start_offset;
+  // Length of the central directory comment.
+  uint16_t comment_length;
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(EocdRecord);
+} __attribute__((packed));
 
-static const uint32_t kCDESignature     = 0x02014b50;
-static const uint32_t kCDELen           = 46;             // excluding variable-len fields
-static const uint32_t kCDEMethod        = 10;             // offset to compression method
-static const uint32_t kCDEModWhen       = 12;             // offset to modification timestamp
-static const uint32_t kCDECRC           = 16;             // offset to entry CRC
-static const uint32_t kCDECompLen       = 20;             // offset to compressed length
-static const uint32_t kCDEUncompLen     = 24;             // offset to uncompressed length
-static const uint32_t kCDENameLen       = 28;             // offset to filename length
-static const uint32_t kCDEExtraLen      = 30;             // offset to extra length
-static const uint32_t kCDECommentLen    = 32;             // offset to comment length
-static const uint32_t kCDELocalOffset   = 42;             // offset to local hdr
+// A structure representing the fixed length fields for a single
+// record in the central directory of the archive. In addition to
+// the fixed length fields listed here, each central directory
+// record contains a variable length "file_name" and "extra_field"
+// whose lengths are given by |file_name_length| and |extra_field_length|
+// respectively.
+struct CentralDirectoryRecord {
+  static const uint32_t kSignature = 0x02014b50;
 
-static const uint32_t kDDOptSignature   = 0x08074b50;     // *OPTIONAL* data descriptor signature
-static const uint32_t kDDSignatureLen   = 4;
-static const uint32_t kDDLen            = 12;
-static const uint32_t kDDMaxLen         = 16;             // max of 16 bytes with a signature, 12 bytes without
-static const uint32_t kDDCrc32          = 0;              // offset to crc32
-static const uint32_t kDDCompLen        = 4;              // offset to compressed length
-static const uint32_t kDDUncompLen      = 8;              // offset to uncompressed length
+  // The start of record signature. Must be |kSignature|.
+  uint32_t record_signature;
+  // Tool version. Ignored by this implementation.
+  uint16_t version_made_by;
+  // Tool version. Ignored by this implementation.
+  uint16_t version_needed;
+  // The "general purpose bit flags" for this entry. The only
+  // flag value that we currently check for is the "data descriptor"
+  // flag.
+  uint16_t gpb_flags;
+  // The compression method for this entry, one of |kCompressStored|
+  // and |kCompressDeflated|.
+  uint16_t compression_method;
+  // The file modification time and date for this entry.
+  uint16_t last_mod_time;
+  uint16_t last_mod_date;
+  // The CRC-32 checksum for this entry.
+  uint32_t crc32;
+  // The compressed size (in bytes) of this entry.
+  uint32_t compressed_size;
+  // The uncompressed size (in bytes) of this entry.
+  uint32_t uncompressed_size;
+  // The length of the entry file name in bytes. The file name
+  // will appear immediately after this record.
+  uint16_t file_name_length;
+  // The length of the extra field info (in bytes). This data
+  // will appear immediately after the entry file name.
+  uint16_t extra_field_length;
+  // The length of the entry comment (in bytes). This data will
+  // appear immediately after the extra field.
+  uint16_t comment_length;
+  // The start disk for this entry. Ignored by this implementation).
+  uint16_t file_start_disk;
+  // File attributes. Ignored by this implementation.
+  uint16_t internal_file_attributes;
+  // File attributes. Ignored by this implementation.
+  uint32_t external_file_attributes;
+  // The offset to the local file header for this entry, from the
+  // beginning of this archive.
+  uint32_t local_file_header_offset;
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(CentralDirectoryRecord);
+} __attribute__((packed));
 
-static const uint32_t kGPBDDFlagMask    = 0x0008;         // mask value that signifies that the entry has a DD
+// The local file header for a given entry. This duplicates information
+// present in the central directory of the archive. It is an error for
+// the information here to be different from the central directory
+// information for a given entry.
+struct LocalFileHeader {
+  static const uint32_t kSignature = 0x04034b50;
 
+  // The local file header signature, must be |kSignature|.
+  uint32_t lfh_signature;
+  // Tool version. Ignored by this implementation.
+  uint16_t version_needed;
+  // The "general purpose bit flags" for this entry. The only
+  // flag value that we currently check for is the "data descriptor"
+  // flag.
+  uint16_t gpb_flags;
+  // The compression method for this entry, one of |kCompressStored|
+  // and |kCompressDeflated|.
+  uint16_t compression_method;
+  // The file modification time and date for this entry.
+  uint16_t last_mod_time;
+  uint16_t last_mod_date;
+  // The CRC-32 checksum for this entry.
+  uint32_t crc32;
+  // The compressed size (in bytes) of this entry.
+  uint32_t compressed_size;
+  // The uncompressed size (in bytes) of this entry.
+  uint32_t uncompressed_size;
+  // The length of the entry file name in bytes. The file name
+  // will appear immediately after this record.
+  uint16_t file_name_length;
+  // The length of the extra field info (in bytes). This data
+  // will appear immediately after the entry file name.
+  uint16_t extra_field_length;
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(LocalFileHeader);
+} __attribute__((packed));
+
+struct DataDescriptor {
+  // The *optional* data descriptor start signature.
+  static const uint32_t kOptSignature = 0x08074b50;
+
+  // CRC-32 checksum of the entry.
+  uint32_t crc32;
+  // Compressed size of the entry.
+  uint32_t compressed_size;
+  // Uncompressed size of the entry.
+  uint32_t uncompressed_size;
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(DataDescriptor);
+} __attribute__((packed));
+
+#undef DISALLOW_IMPLICIT_CONSTRUCTORS
+
+static const uint32_t kGPBDDFlagMask = 0x0008;         // mask value that signifies that the entry has a DD
 static const uint32_t kMaxErrorLen = 1024;
 
+// The maximum size of a central directory or a file
+// comment in bytes.
+static const uint32_t kMaxCommentLen = 65535;
+
+// The maximum number of bytes to scan backwards for the EOCD start.
+static const uint32_t kMaxEOCDSearch = kMaxCommentLen + sizeof(EocdRecord);
+
 static const char* kErrorMessages[] = {
   "Unknown return code.",
   "Iteration ended",
@@ -217,8 +335,7 @@
     ssize_t actual = TEMP_FAILURE_RETRY(read(fd, buf, get_size));
 
     if (actual != get_size) {
-      ALOGW("CopyFileToFile: copy read failed (%d vs %zd)",
-          (int) actual, get_size);
+      ALOGW("CopyFileToFile: copy read failed (" ZD " vs " ZD ")", actual, get_size);
       return kIoError;
     }
 
@@ -279,7 +396,7 @@
     ent = (ent + 1) & (hash_table_size - 1);
   }
 
-  ALOGV("Zip: Unable to find entry %.*s", name_length, name);
+  ALOGV("Zip: Unable to find entry %.*s", length, name);
   return kEntryNotFound;
 }
 
@@ -310,39 +427,21 @@
   return 0;
 }
 
-/*
- * Get 2 little-endian bytes.
- */
-static uint16_t get2LE(const uint8_t* src) {
-  return src[0] | (src[1] << 8);
-}
-
-/*
- * Get 4 little-endian bytes.
- */
-static uint32_t get4LE(const uint8_t* src) {
-  uint32_t result;
-
-  result = src[0];
-  result |= src[1] << 8;
-  result |= src[2] << 16;
-  result |= src[3] << 24;
-
-  return result;
-}
-
 static int32_t MapCentralDirectory0(int fd, const char* debug_file_name,
                                     ZipArchive* archive, off64_t file_length,
-                                    uint32_t read_amount, uint8_t* scan_buffer) {
+                                    off64_t read_amount, uint8_t* scan_buffer) {
   const off64_t search_start = file_length - read_amount;
 
   if (lseek64(fd, search_start, SEEK_SET) != search_start) {
-    ALOGW("Zip: seek %lld failed: %s", search_start, strerror(errno));
+    ALOGW("Zip: seek %" PRId64 " failed: %s", static_cast<int64_t>(search_start),
+          strerror(errno));
     return kIoError;
   }
-  ssize_t actual = TEMP_FAILURE_RETRY(read(fd, scan_buffer, read_amount));
-  if (actual != (ssize_t) read_amount) {
-    ALOGW("Zip: read %zd failed: %s", read_amount, strerror(errno));
+  ssize_t actual = TEMP_FAILURE_RETRY(
+      read(fd, scan_buffer, static_cast<size_t>(read_amount)));
+  if (actual != static_cast<ssize_t>(read_amount)) {
+    ALOGW("Zip: read %" PRId64 " failed: %s", static_cast<int64_t>(read_amount),
+          strerror(errno));
     return kIoError;
   }
 
@@ -352,9 +451,10 @@
    * doing an initial minimal read; if we don't find it, retry with a
    * second read as above.)
    */
-  int i;
-  for (i = read_amount - kEOCDLen; i >= 0; i--) {
-    if (scan_buffer[i] == 0x50 && get4LE(&scan_buffer[i]) == kEOCDSignature) {
+  int i = read_amount - sizeof(EocdRecord);
+  for (; i >= 0; i--) {
+    if (scan_buffer[i] == 0x50 &&
+        ((*reinterpret_cast<uint32_t*>(&scan_buffer[i])) == EocdRecord::kSignature)) {
       ALOGV("+++ Found EOCD at buf+%d", i);
       break;
     }
@@ -365,46 +465,52 @@
   }
 
   const off64_t eocd_offset = search_start + i;
-  const uint8_t* eocd_ptr = scan_buffer + i;
-
-  assert(eocd_offset < file_length);
+  const EocdRecord* eocd = reinterpret_cast<const EocdRecord*>(scan_buffer + i);
+  /*
+   * Verify that there's no trailing space at the end of the central directory
+   * and its comment.
+   */
+  const off64_t calculated_length = eocd_offset + sizeof(EocdRecord)
+      + eocd->comment_length;
+  if (calculated_length != file_length) {
+    ALOGW("Zip: %" PRId64 " extraneous bytes at the end of the central directory",
+          static_cast<int64_t>(file_length - calculated_length));
+    return kInvalidFile;
+  }
 
   /*
    * Grab the CD offset and size, and the number of entries in the
-   * archive.  Verify that they look reasonable. Widen dir_size and
-   * dir_offset to the file offset type.
+   * archive and verify that they look reasonable.
    */
-  const uint16_t num_entries = get2LE(eocd_ptr + kEOCDNumEntries);
-  const off64_t dir_size = get4LE(eocd_ptr + kEOCDSize);
-  const off64_t dir_offset = get4LE(eocd_ptr + kEOCDFileOffset);
-
-  if (dir_offset + dir_size > eocd_offset) {
-    ALOGW("Zip: bad offsets (dir %lld, size %lld, eocd %lld)",
-        dir_offset, dir_size, eocd_offset);
+  if (eocd->cd_start_offset + eocd->cd_size > eocd_offset) {
+    ALOGW("Zip: bad offsets (dir %" PRIu32 ", size %" PRIu32 ", eocd %" PRId64 ")",
+        eocd->cd_start_offset, eocd->cd_size, static_cast<int64_t>(eocd_offset));
     return kInvalidOffset;
   }
-  if (num_entries == 0) {
+  if (eocd->num_records == 0) {
     ALOGW("Zip: empty archive?");
     return kEmptyArchive;
   }
 
-  ALOGV("+++ num_entries=%d dir_size=%d dir_offset=%d", num_entries, dir_size,
-      dir_offset);
+  ALOGV("+++ num_entries=%" PRIu32 "dir_size=%" PRIu32 " dir_offset=%" PRIu32,
+        eocd->num_records, eocd->cd_size, eocd->cd_start_offset);
 
   /*
    * It all looks good.  Create a mapping for the CD, and set the fields
    * in archive.
    */
-  android::FileMap* map = MapFileSegment(fd, dir_offset, dir_size,
-                                         true /* read only */, debug_file_name);
+  android::FileMap* map = MapFileSegment(fd,
+      static_cast<off64_t>(eocd->cd_start_offset),
+      static_cast<size_t>(eocd->cd_size),
+      true /* read only */, debug_file_name);
   if (map == NULL) {
     archive->directory_map = NULL;
     return kMmapFailed;
   }
 
   archive->directory_map = map;
-  archive->num_entries = num_entries;
-  archive->directory_offset = dir_offset;
+  archive->num_entries = eocd->num_records;
+  archive->directory_offset = eocd->cd_start_offset;
 
   return 0;
 }
@@ -430,12 +536,12 @@
   }
 
   if (file_length > (off64_t) 0xffffffff) {
-    ALOGV("Zip: zip file too long %d", file_length);
+    ALOGV("Zip: zip file too long %" PRId64, static_cast<int64_t>(file_length));
     return kInvalidFile;
   }
 
-  if (file_length < (int64_t) kEOCDLen) {
-    ALOGV("Zip: length %ld is too small to be zip", file_length);
+  if (file_length < static_cast<off64_t>(sizeof(EocdRecord))) {
+    ALOGV("Zip: length %" PRId64 " is too small to be zip", static_cast<int64_t>(file_length));
     return kInvalidFile;
   }
 
@@ -451,12 +557,12 @@
    *
    * We start by pulling in the last part of the file.
    */
-  uint32_t read_amount = kMaxEOCDSearch;
-  if (file_length < (off64_t) read_amount) {
+  off64_t read_amount = kMaxEOCDSearch;
+  if (file_length < read_amount) {
     read_amount = file_length;
   }
 
-  uint8_t* scan_buffer = (uint8_t*) malloc(read_amount);
+  uint8_t* scan_buffer = reinterpret_cast<uint8_t*>(malloc(read_amount));
   int32_t result = MapCentralDirectory0(fd, debug_file_name, archive,
                                         file_length, read_amount, scan_buffer);
 
@@ -472,9 +578,9 @@
  */
 static int32_t ParseZipArchive(ZipArchive* archive) {
   int32_t result = -1;
-  const uint8_t* cd_ptr = (const uint8_t*) archive->directory_map->getDataPtr();
-  size_t cd_length = archive->directory_map->getDataLength();
-  uint16_t num_entries = archive->num_entries;
+  const uint8_t* const cd_ptr = (const uint8_t*) archive->directory_map->getDataPtr();
+  const size_t cd_length = archive->directory_map->getDataLength();
+  const uint16_t num_entries = archive->num_entries;
 
   /*
    * Create hash table.  We have a minimum 75% load factor, possibly as
@@ -489,45 +595,49 @@
    * Walk through the central directory, adding entries to the hash
    * table and verifying values.
    */
+  const uint8_t* const cd_end = cd_ptr + cd_length;
   const uint8_t* ptr = cd_ptr;
   for (uint16_t i = 0; i < num_entries; i++) {
-    if (get4LE(ptr) != kCDESignature) {
-      ALOGW("Zip: missed a central dir sig (at %d)", i);
+    const CentralDirectoryRecord* cdr =
+        reinterpret_cast<const CentralDirectoryRecord*>(ptr);
+    if (cdr->record_signature != CentralDirectoryRecord::kSignature) {
+      ALOGW("Zip: missed a central dir sig (at %" PRIu16 ")", i);
       goto bail;
     }
 
-    if (ptr + kCDELen > cd_ptr + cd_length) {
-      ALOGW("Zip: ran off the end (at %d)", i);
+    if (ptr + sizeof(CentralDirectoryRecord) > cd_end) {
+      ALOGW("Zip: ran off the end (at %" PRIu16 ")", i);
       goto bail;
     }
 
-    const off64_t local_header_offset = get4LE(ptr + kCDELocalOffset);
+    const off64_t local_header_offset = cdr->local_file_header_offset;
     if (local_header_offset >= archive->directory_offset) {
-      ALOGW("Zip: bad LFH offset %lld at entry %d", local_header_offset, i);
+      ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16, (int64_t)local_header_offset, i);
       goto bail;
     }
 
-    const uint16_t file_name_length = get2LE(ptr + kCDENameLen);
-    const uint16_t extra_length = get2LE(ptr + kCDEExtraLen);
-    const uint16_t comment_length = get2LE(ptr + kCDECommentLen);
+    const uint16_t file_name_length = cdr->file_name_length;
+    const uint16_t extra_length = cdr->extra_field_length;
+    const uint16_t comment_length = cdr->comment_length;
 
     /* add the CDE filename to the hash table */
+    const char* file_name = reinterpret_cast<const char *>(ptr + sizeof(CentralDirectoryRecord));
     const int add_result = AddToHash(archive->hash_table,
-        archive->hash_table_size, (const char*) ptr + kCDELen, file_name_length);
+        archive->hash_table_size, file_name, file_name_length);
     if (add_result) {
       ALOGW("Zip: Error adding entry to hash table %d", add_result);
       result = add_result;
       goto bail;
     }
 
-    ptr += kCDELen + file_name_length + extra_length + comment_length;
-    if ((size_t)(ptr - cd_ptr) > cd_length) {
-      ALOGW("Zip: bad CD advance (%d vs %zd) at entry %d",
-        (int) (ptr - cd_ptr), cd_length, i);
+    ptr += sizeof(CentralDirectoryRecord) + file_name_length + extra_length + comment_length;
+    if ((ptr - cd_ptr) > static_cast<int64_t>(cd_length)) {
+      ALOGW("Zip: bad CD advance (%tu vs %zu) at entry %" PRIu16,
+          ptr - cd_ptr, cd_length, i);
       goto bail;
     }
   }
-  ALOGV("+++ zip good scan %d entries", num_entries);
+  ALOGV("+++ zip good scan %" PRIu16 " entries", num_entries);
 
   result = 0;
 
@@ -591,32 +701,24 @@
     archive->directory_map->release();
   }
   free(archive->hash_table);
-
-  /* ensure nobody tries to use the ZipArchive after it's closed */
-  archive->directory_offset = -1;
-  archive->fd = -1;
-  archive->num_entries = -1;
-  archive->hash_table_size = -1;
-  archive->hash_table = NULL;
+  free(archive);
 }
 
 static int32_t UpdateEntryFromDataDescriptor(int fd,
                                              ZipEntry *entry) {
-  uint8_t ddBuf[kDDMaxLen];
+  uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)];
   ssize_t actual = TEMP_FAILURE_RETRY(read(fd, ddBuf, sizeof(ddBuf)));
   if (actual != sizeof(ddBuf)) {
     return kIoError;
   }
 
-  const uint32_t ddSignature = get4LE(ddBuf);
-  uint16_t ddOffset = 0;
-  if (ddSignature == kDDOptSignature) {
-    ddOffset = 4;
-  }
+  const uint32_t ddSignature = *(reinterpret_cast<const uint32_t*>(ddBuf));
+  const uint16_t offset = (ddSignature == DataDescriptor::kOptSignature) ? 4 : 0;
+  const DataDescriptor* descriptor = reinterpret_cast<const DataDescriptor*>(ddBuf + offset);
 
-  entry->crc32 = get4LE(ddBuf + ddOffset + kDDCrc32);
-  entry->compressed_length = get4LE(ddBuf + ddOffset + kDDCompLen);
-  entry->uncompressed_length = get4LE(ddBuf + ddOffset + kDDUncompLen);
+  entry->crc32 = descriptor->crc32;
+  entry->compressed_length = descriptor->compressed_size;
+  entry->uncompressed_length = descriptor->uncompressed_size;
 
   return 0;
 }
@@ -636,7 +738,7 @@
   // is Windows. Only recent versions of windows support unix like forks,
   // and even there the semantics are quite different.
   if (lseek64(fd, off, SEEK_SET) != off) {
-    ALOGW("Zip: failed seek to offset %lld", off);
+    ALOGW("Zip: failed seek to offset %" PRId64, off);
     return kIoError;
   }
 
@@ -652,19 +754,22 @@
   // Recover the start of the central directory entry from the filename
   // pointer.  The filename is the first entry past the fixed-size data,
   // so we can just subtract back from that.
-  const unsigned char* ptr = (const unsigned char*) name;
-  ptr -= kCDELen;
+  const uint8_t* ptr = reinterpret_cast<const uint8_t*>(name);
+  ptr -= sizeof(CentralDirectoryRecord);
 
   // This is the base of our mmapped region, we have to sanity check that
   // the name that's in the hash table is a pointer to a location within
   // this mapped region.
-  const unsigned char* base_ptr = (const unsigned char*)
-    archive->directory_map->getDataPtr();
+  const uint8_t* base_ptr = reinterpret_cast<const uint8_t*>(
+    archive->directory_map->getDataPtr());
   if (ptr < base_ptr || ptr > base_ptr + archive->directory_map->getDataLength()) {
     ALOGW("Zip: Invalid entry pointer");
     return kInvalidOffset;
   }
 
+  const CentralDirectoryRecord *cdr =
+      reinterpret_cast<const CentralDirectoryRecord*>(ptr);
+
   // The offset of the start of the central directory in the zipfile.
   // We keep this lying around so that we can sanity check all our lengths
   // and our per-file structures.
@@ -673,52 +778,48 @@
   // Fill out the compression method, modification time, crc32
   // and other interesting attributes from the central directory. These
   // will later be compared against values from the local file header.
-  data->method = get2LE(ptr + kCDEMethod);
-  data->mod_time = get4LE(ptr + kCDEModWhen);
-  data->crc32 = get4LE(ptr + kCDECRC);
-  data->compressed_length = get4LE(ptr + kCDECompLen);
-  data->uncompressed_length = get4LE(ptr + kCDEUncompLen);
+  data->method = cdr->compression_method;
+  data->mod_time = cdr->last_mod_time;
+  data->crc32 = cdr->crc32;
+  data->compressed_length = cdr->compressed_size;
+  data->uncompressed_length = cdr->uncompressed_size;
 
   // Figure out the local header offset from the central directory. The
   // actual file data will begin after the local header and the name /
   // extra comments.
-  const off64_t local_header_offset = get4LE(ptr + kCDELocalOffset);
-  if (local_header_offset + (off64_t) kLFHLen >= cd_offset) {
+  const off64_t local_header_offset = cdr->local_file_header_offset;
+  if (local_header_offset + static_cast<off64_t>(sizeof(LocalFileHeader)) >= cd_offset) {
     ALOGW("Zip: bad local hdr offset in zip");
     return kInvalidOffset;
   }
 
-  uint8_t lfh_buf[kLFHLen];
+  uint8_t lfh_buf[sizeof(LocalFileHeader)];
   ssize_t actual = ReadAtOffset(archive->fd, lfh_buf, sizeof(lfh_buf),
                                  local_header_offset);
   if (actual != sizeof(lfh_buf)) {
-    ALOGW("Zip: failed reading lfh name from offset %lld", local_header_offset);
+    ALOGW("Zip: failed reading lfh name from offset %" PRId64, (int64_t)local_header_offset);
     return kIoError;
   }
 
-  if (get4LE(lfh_buf) != kLFHSignature) {
-    ALOGW("Zip: didn't find signature at start of lfh, offset=%lld",
-        local_header_offset);
+  const LocalFileHeader *lfh = reinterpret_cast<const LocalFileHeader*>(lfh_buf);
+
+  if (lfh->lfh_signature != LocalFileHeader::kSignature) {
+    ALOGW("Zip: didn't find signature at start of lfh, offset=%" PRId64,
+        static_cast<int64_t>(local_header_offset));
     return kInvalidOffset;
   }
 
   // Paranoia: Match the values specified in the local file header
   // to those specified in the central directory.
-  const uint16_t lfhGpbFlags = get2LE(lfh_buf + kLFHGPBFlags);
-  const uint16_t lfhNameLen = get2LE(lfh_buf + kLFHNameLen);
-  const uint16_t lfhExtraLen = get2LE(lfh_buf + kLFHExtraLen);
-
-  if ((lfhGpbFlags & kGPBDDFlagMask) == 0) {
-    const uint32_t lfhCrc = get4LE(lfh_buf + kLFHCRC);
-    const uint32_t lfhCompLen = get4LE(lfh_buf + kLFHCompLen);
-    const uint32_t lfhUncompLen = get4LE(lfh_buf + kLFHUncompLen);
-
+  if ((lfh->gpb_flags & kGPBDDFlagMask) == 0) {
     data->has_data_descriptor = 0;
-    if (data->compressed_length != lfhCompLen || data->uncompressed_length != lfhUncompLen
-        || data->crc32 != lfhCrc) {
-      ALOGW("Zip: size/crc32 mismatch. expected {%d, %d, %x}, was {%d, %d, %x}",
+    if (data->compressed_length != lfh->compressed_size
+        || data->uncompressed_length != lfh->uncompressed_size
+        || data->crc32 != lfh->crc32) {
+      ALOGW("Zip: size/crc32 mismatch. expected {%" PRIu32 ", %" PRIu32
+        ", %" PRIx32 "}, was {%" PRIu32 ", %" PRIu32 ", %" PRIx32 "}",
         data->compressed_length, data->uncompressed_length, data->crc32,
-        lfhCompLen, lfhUncompLen, lfhCrc);
+        lfh->compressed_size, lfh->uncompressed_size, lfh->crc32);
       return kInconsistentInformation;
     }
   } else {
@@ -727,9 +828,9 @@
 
   // Check that the local file header name matches the declared
   // name in the central directory.
-  if (lfhNameLen == nameLen) {
-    const off64_t name_offset = local_header_offset + kLFHLen;
-    if (name_offset + lfhNameLen >= cd_offset) {
+  if (lfh->file_name_length == nameLen) {
+    const off64_t name_offset = local_header_offset + sizeof(LocalFileHeader);
+    if (name_offset + lfh->file_name_length >= cd_offset) {
       ALOGW("Zip: Invalid declared length");
       return kInvalidOffset;
     }
@@ -739,7 +840,7 @@
                                   name_offset);
 
     if (actual != nameLen) {
-      ALOGW("Zip: failed reading lfh name from offset %lld", name_offset);
+      ALOGW("Zip: failed reading lfh name from offset %" PRId64, (int64_t)name_offset);
       free(name_buf);
       return kIoError;
     }
@@ -755,22 +856,23 @@
     return kInconsistentInformation;
   }
 
-  const off64_t data_offset = local_header_offset + kLFHLen + lfhNameLen + lfhExtraLen;
+  const off64_t data_offset = local_header_offset + sizeof(LocalFileHeader)
+      + lfh->file_name_length + lfh->extra_field_length;
   if (data_offset > cd_offset) {
-    ALOGW("Zip: bad data offset %lld in zip", (off64_t) data_offset);
+    ALOGW("Zip: bad data offset %" PRId64 " in zip", (int64_t)data_offset);
     return kInvalidOffset;
   }
 
   if ((off64_t)(data_offset + data->compressed_length) > cd_offset) {
-    ALOGW("Zip: bad compressed length in zip (%lld + %zd > %lld)",
-      data_offset, data->compressed_length, cd_offset);
+    ALOGW("Zip: bad compressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
+      (int64_t)data_offset, data->compressed_length, (int64_t)cd_offset);
     return kInvalidOffset;
   }
 
   if (data->method == kCompressStored &&
     (off64_t)(data_offset + data->uncompressed_length) > cd_offset) {
-     ALOGW("Zip: bad uncompressed length in zip (%lld + %zd > %lld)",
-       data_offset, data->uncompressed_length, cd_offset);
+     ALOGW("Zip: bad uncompressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
+       (int64_t)data_offset, data->uncompressed_length, (int64_t)cd_offset);
      return kInvalidOffset;
   }
 
@@ -906,10 +1008,10 @@
   do {
     /* read as much as we can */
     if (zstream.avail_in == 0) {
-      const ssize_t getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
-      const ssize_t actual = TEMP_FAILURE_RETRY(read(fd, read_buf, getSize));
+      const ZD_TYPE getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
+      const ZD_TYPE actual = TEMP_FAILURE_RETRY(read(fd, read_buf, getSize));
       if (actual != getSize) {
-        ALOGW("Zip: inflate read failed (%d vs %zd)", actual, getSize);
+        ALOGW("Zip: inflate read failed (" ZD " vs " ZD ")", actual, getSize);
         result = kIoError;
         goto z_bail;
       }
@@ -952,7 +1054,7 @@
   *crc_out = zstream.adler;
 
   if (zstream.total_out != uncompressed_length || compressed_length != 0) {
-    ALOGW("Zip: size mismatch on inflated file (%ld vs %zd)",
+    ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu32 ")",
         zstream.total_out, uncompressed_length);
     result = kInconsistentInformation;
     goto z_bail;
@@ -973,7 +1075,7 @@
   off64_t data_offset = entry->offset;
 
   if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) {
-    ALOGW("Zip: lseek to data at %lld failed", (off64_t) data_offset);
+    ALOGW("Zip: lseek to data at %" PRId64 " failed", (int64_t)data_offset);
     return kIoError;
   }
 
@@ -996,7 +1098,7 @@
   // TODO: Fix this check by passing the right flags to inflate2 so that
   // it calculates the CRC for us.
   if (entry->crc32 != crc && false) {
-    ALOGW("Zip: crc mismatch: expected %u, was %llu", entry->crc32, crc);
+    ALOGW("Zip: crc mismatch: expected %" PRIu32 ", was %" PRIu64, entry->crc32, crc);
     return kInconsistentInformation;
   }
 
@@ -1016,8 +1118,8 @@
 
   int result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
   if (result == -1) {
-    ALOGW("Zip: unable to truncate file to %lld: %s", declared_length + current_offset,
-          strerror(errno));
+    ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
+          (int64_t)(declared_length + current_offset), strerror(errno));
     return kIoError;
   }
 
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 3082216..875b6de 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -140,11 +140,7 @@
   CloseArchive(handle);
 }
 
-TEST(ziparchive, EmptyEntries) {
-  char temp_file_pattern[] = "empty_entries_test_XXXXXX";
-  int fd = mkstemp(temp_file_pattern);
-  ASSERT_NE(-1, fd);
-  const uint32_t data[] = {
+static const uint32_t kEmptyEntriesZip[] = {
       0x04034b50, 0x0000000a, 0x63600000, 0x00004438, 0x00000000, 0x00000000,
       0x00090000, 0x6d65001c, 0x2e797470, 0x55747874, 0x03000954, 0x52e25c13,
       0x52e25c24, 0x000b7875, 0x42890401, 0x88040000, 0x50000013, 0x1e02014b,
@@ -152,8 +148,28 @@
       0x00001800, 0x00000000, 0xa0000000, 0x00000081, 0x706d6500, 0x742e7974,
       0x54557478, 0x13030005, 0x7552e25c, 0x01000b78, 0x00428904, 0x13880400,
       0x4b500000, 0x00000605, 0x00010000, 0x004f0001, 0x00430000, 0x00000000 };
-  const ssize_t file_size = 168;
-  ASSERT_EQ(file_size, TEMP_FAILURE_RETRY(write(fd, data, file_size)));
+
+static int make_temporary_file(const char* file_name_pattern) {
+  char full_path[1024];
+  // Account for differences between the host and the target.
+  //
+  // TODO: Maybe reuse bionic/tests/TemporaryFile.h.
+  snprintf(full_path, sizeof(full_path), "/data/local/tmp/%s", file_name_pattern);
+  int fd = mkstemp(full_path);
+  if (fd == -1) {
+    snprintf(full_path, sizeof(full_path), "/tmp/%s", file_name_pattern);
+    fd = mkstemp(full_path);
+  }
+
+  return fd;
+}
+
+TEST(ziparchive, EmptyEntries) {
+  char temp_file_pattern[] = "empty_entries_test_XXXXXX";
+  int fd = make_temporary_file(temp_file_pattern);
+  ASSERT_NE(-1, fd);
+  const ssize_t file_size = sizeof(kEmptyEntriesZip);
+  ASSERT_EQ(file_size, TEMP_FAILURE_RETRY(write(fd, kEmptyEntriesZip, file_size)));
 
   ZipArchiveHandle handle;
   ASSERT_EQ(0, OpenArchiveFd(fd, "EmptyEntriesTest", &handle));
@@ -165,7 +181,7 @@
   ASSERT_EQ(0, ExtractToMemory(handle, &entry, buffer, 1));
 
   char output_file_pattern[] = "empty_entries_output_XXXXXX";
-  int output_fd = mkstemp(output_file_pattern);
+  int output_fd = make_temporary_file(output_file_pattern);
   ASSERT_NE(-1, output_fd);
   ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, output_fd));
 
@@ -177,9 +193,25 @@
   close(output_fd);
 }
 
+TEST(ziparchive, TrailerAfterEOCD) {
+  char temp_file_pattern[] = "trailer_after_eocd_test_XXXXXX";
+  int fd = make_temporary_file(temp_file_pattern);
+  ASSERT_NE(-1, fd);
+
+  // Create a file with 8 bytes of random garbage.
+  static const uint8_t trailer[] = { 'A' ,'n', 'd', 'r', 'o', 'i', 'd', 'z' };
+  const ssize_t file_size = sizeof(kEmptyEntriesZip);
+  const ssize_t trailer_size = sizeof(trailer);
+  ASSERT_EQ(file_size, TEMP_FAILURE_RETRY(write(fd, kEmptyEntriesZip, file_size)));
+  ASSERT_EQ(trailer_size, TEMP_FAILURE_RETRY(write(fd, trailer, trailer_size)));
+
+  ZipArchiveHandle handle;
+  ASSERT_GT(0, OpenArchiveFd(fd, "EmptyEntriesTest", &handle));
+}
+
 TEST(ziparchive, ExtractToFile) {
   char kTempFilePattern[] = "zip_archive_input_XXXXXX";
-  int fd = mkstemp(kTempFilePattern);
+  int fd = make_temporary_file(kTempFilePattern);
   ASSERT_NE(-1, fd);
   const uint8_t data[8] = { '1', '2', '3', '4', '5', '6', '7', '8' };
   const ssize_t data_size = sizeof(data);
@@ -209,7 +241,8 @@
                       sizeof(kATxtContents)));
 
   // Assert that the total length of the file is sane
-  ASSERT_EQ(data_size + sizeof(kATxtContents), lseek64(fd, 0, SEEK_END));
+  ASSERT_EQ(data_size + static_cast<ssize_t>(sizeof(kATxtContents)),
+            lseek64(fd, 0, SEEK_END));
 
   close(fd);
 }
@@ -247,4 +280,3 @@
 
   return RUN_ALL_TESTS();
 }
-
diff --git a/libzipfile/Android.mk b/libzipfile/Android.mk
index d2d758c..12a2229 100644
--- a/libzipfile/Android.mk
+++ b/libzipfile/Android.mk
@@ -14,6 +14,10 @@
 
 LOCAL_C_INCLUDES += external/zlib
 
+LOCAL_CFLAGS := -Werror
+
+LOCAL_MULTILIB := both
+
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 # build device static library
@@ -30,6 +34,8 @@
 
 LOCAL_C_INCLUDES += external/zlib
 
+LOCAL_CFLAGS := -Werror
+
 include $(BUILD_STATIC_LIBRARY)
 
 
@@ -45,4 +51,6 @@
 
 LOCAL_C_INCLUDES += external/zlib
 
+LOCAL_CFLAGS := -Werror
+
 include $(BUILD_HOST_EXECUTABLE)
diff --git a/libzipfile/centraldir.c b/libzipfile/centraldir.c
index 911e2b9..69cf47a 100644
--- a/libzipfile/centraldir.c
+++ b/libzipfile/centraldir.c
@@ -3,6 +3,8 @@
 #include <string.h>

 #include <stdlib.h>

 

+#include <utils/Compat.h>

+

 enum {

     // finding the directory

     CD_SIGNATURE = 0x06054b50,

@@ -66,24 +68,10 @@
 {

     const unsigned char* p;

 

-    unsigned short  versionMadeBy;

-    unsigned short  versionToExtract;

-    unsigned short  gpBitFlag;

-    unsigned short  compressionMethod;

-    unsigned short  lastModFileTime;

-    unsigned short  lastModFileDate;

-    unsigned long   crc32;

     unsigned short  extraFieldLength;

     unsigned short  fileCommentLength;

-    unsigned short  diskNumberStart;

-    unsigned short  internalAttrs;

-    unsigned long   externalAttrs;

     unsigned long   localHeaderRelOffset;

-    const unsigned char*  extraField;

-    const unsigned char*  fileComment;

     unsigned int dataOffset;

-    unsigned short lfhExtraFieldSize;

-

 

     p = *buf;

 

@@ -97,21 +85,12 @@
         return -1;

     }

 

-    versionMadeBy = read_le_short(&p[0x04]);

-    versionToExtract = read_le_short(&p[0x06]);

-    gpBitFlag = read_le_short(&p[0x08]);

     entry->compressionMethod = read_le_short(&p[0x0a]);

-    lastModFileTime = read_le_short(&p[0x0c]);

-    lastModFileDate = read_le_short(&p[0x0e]);

-    crc32 = read_le_int(&p[0x10]);

     entry->compressedSize = read_le_int(&p[0x14]);

     entry->uncompressedSize = read_le_int(&p[0x18]);

     entry->fileNameLength = read_le_short(&p[0x1c]);

     extraFieldLength = read_le_short(&p[0x1e]);

     fileCommentLength = read_le_short(&p[0x20]);

-    diskNumberStart = read_le_short(&p[0x22]);

-    internalAttrs = read_le_short(&p[0x24]);

-    externalAttrs = read_le_int(&p[0x26]);

     localHeaderRelOffset = read_le_int(&p[0x2a]);

 

     p += ENTRY_LEN;

@@ -125,19 +104,9 @@
     p += entry->fileNameLength;

 

     // extra field

-    if (extraFieldLength != 0) {

-        extraField = p;

-    } else {

-        extraField = NULL;

-    }

     p += extraFieldLength;

 

     // comment, if any

-    if (fileCommentLength != 0) {

-        fileComment = p;

-    } else {

-        fileComment = NULL;

-    }

     p += fileCommentLength;

 

     *buf = p;

@@ -183,7 +152,7 @@
     int err;

 

     const unsigned char* buf = file->buf;

-    ssize_t bufsize = file->bufsize;

+    ZD_TYPE bufsize = file->bufsize;

     const unsigned char* eocd;

     const unsigned char* p;

     const unsigned char* start;

@@ -192,7 +161,7 @@
 

     // too small to be a ZIP archive?

     if (bufsize < EOCD_LEN) {

-        fprintf(stderr, "Length is %zd -- too small\n", bufsize);

+        fprintf(stderr, "Length is " ZD " -- too small\n", bufsize);

         goto bail;

     }

 

diff --git a/libzipfile/zipfile.c b/libzipfile/zipfile.c
index a401a9b..b903fcf 100644
--- a/libzipfile/zipfile.c
+++ b/libzipfile/zipfile.c
@@ -79,7 +79,6 @@
 uninflate(unsigned char* out, int unlen, const unsigned char* in, int clen)
 {
     z_stream zstream;
-    unsigned long crc;
     int err = 0;
     int zerr;
 
diff --git a/logcat/Android.mk b/logcat/Android.mk
index b5e27eb..f46a4de 100644
--- a/logcat/Android.mk
+++ b/logcat/Android.mk
@@ -7,7 +7,9 @@
 
 LOCAL_SHARED_LIBRARIES := liblog
 
-LOCAL_MODULE:= logcat
+LOCAL_MODULE := logcat
+
+LOCAL_CFLAGS := -Werror
 
 include $(BUILD_EXECUTABLE)
 
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 3c33938..7c6af42 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -17,6 +17,7 @@
 
 #include <cutils/sockets.h>
 #include <log/log.h>
+#include <log/log_read.h>
 #include <log/logger.h>
 #include <log/logd.h>
 #include <log/logprint.h>
@@ -225,11 +226,21 @@
                     "  -t <count>      print only the most recent <count> lines (implies -d)\n"
                     "  -T <count>      print only the most recent <count> lines (does not imply -d)\n"
                     "  -g              get the size of the log's ring buffer and exit\n"
-                    "  -b <buffer>     Request alternate ring buffer, 'main', 'system', 'radio'\n"
-                    "                  or 'events'. Multiple -b parameters are allowed and the\n"
-                    "                  results are interleaved. The default is -b main -b system.\n"
-                    "  -B              output the log in binary");
-
+                    "  -b <buffer>     Request alternate ring buffer, 'main', 'system', 'radio',\n"
+                    "                  'events', 'crash' or 'all'. Multiple -b parameters are\n"
+                    "                  allowed and results are interleaved. The default is\n"
+                    "                  -b main -b system -b crash.\n"
+                    "  -B              output the log in binary.\n"
+                    "  -S              output statistics.\n"
+                    "  -G <size>       set size of log ring buffer, may suffix with K or M.\n"
+                    "  -p              print prune white and ~black list. Service is specified as\n"
+                    "                  UID, UID/PID or /PID. Weighed for quicker pruning if prefix\n"
+                    "                  with ~, otherwise weighed for longevity if unadorned. All\n"
+                    "                  other pruning activity is oldest first. Special case ~!\n"
+                    "                  represents an automatic quicker pruning for the noisiest\n"
+                    "                  UID as determined by the current statistics.\n"
+                    "  -P '<list> ...' set prune white and ~black list, using same format as\n"
+                    "                  printed above. Must be quoted.\n");
 
     fprintf(stderr,"\nfilterspecs are a series of \n"
                    "  <tag>[:priority]\n\n"
@@ -270,7 +281,29 @@
     return 0;
 }
 
-extern "C" void logprint_run_tests(void);
+static const char multipliers[][2] = {
+    { "" },
+    { "K" },
+    { "M" },
+    { "G" }
+};
+
+static unsigned long value_of_size(unsigned long value)
+{
+    for (unsigned i = 0;
+            (i < sizeof(multipliers)/sizeof(multipliers[0])) && (value >= 1024);
+            value /= 1024, ++i) ;
+    return value;
+}
+
+static const char *multiplier_of_size(unsigned long value)
+{
+    unsigned i;
+    for (i = 0;
+            (i < sizeof(multipliers)/sizeof(multipliers[0])) && (value >= 1024);
+            value /= 1024, ++i) ;
+    return multipliers[i];
+}
 
 int main(int argc, char **argv)
 {
@@ -278,23 +311,23 @@
     int hasSetLogFormat = 0;
     int clearLog = 0;
     int getLogSize = 0;
+    unsigned long setLogSize = 0;
+    int getPruneList = 0;
+    char *setPruneList = NULL;
+    int printStatistics = 0;
     int mode = O_RDONLY;
     const char *forceFilters = NULL;
     log_device_t* devices = NULL;
     log_device_t* dev;
     bool needBinary = false;
     struct logger_list *logger_list;
-    int tail_lines = 0;
+    unsigned int tail_lines = 0;
+    log_time tail_time(log_time::EPOCH);
 
     signal(SIGPIPE, exit);
 
     g_logformat = android_log_format_new();
 
-    if (argc == 2 && 0 == strcmp(argv[1], "--test")) {
-        logprint_run_tests();
-        exit(0);
-    }
-
     if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
         android::show_help(argv[0]);
         exit(0);
@@ -303,7 +336,7 @@
     for (;;) {
         int ret;
 
-        ret = getopt(argc, argv, "cdt:T:gsQf:r::n:v:b:B");
+        ret = getopt(argc, argv, "cdt:T:gG:sQf:r:n:v:b:BSpP:");
 
         if (ret < 0) {
             break;
@@ -328,14 +361,124 @@
                 mode = O_RDONLY | O_NDELAY;
                 /* FALLTHRU */
             case 'T':
-                tail_lines = atoi(optarg);
+                if (strspn(optarg, "0123456789") != strlen(optarg)) {
+                    char *cp = tail_time.strptime(optarg,
+                                                  log_time::default_format);
+                    if (!cp) {
+                        fprintf(stderr,
+                                "ERROR: -%c \"%s\" not in \"%s\" time format\n",
+                                ret, optarg, log_time::default_format);
+                        exit(1);
+                    }
+                    if (*cp) {
+                        char c = *cp;
+                        *cp = '\0';
+                        fprintf(stderr,
+                                "WARNING: -%c \"%s\"\"%c%s\" time truncated\n",
+                                ret, optarg, c, cp + 1);
+                        *cp = c;
+                    }
+                } else {
+                    tail_lines = atoi(optarg);
+                    if (!tail_lines) {
+                        fprintf(stderr,
+                                "WARNING: -%c %s invalid, setting to 1\n",
+                                ret, optarg);
+                        tail_lines = 1;
+                    }
+                }
             break;
 
             case 'g':
                 getLogSize = 1;
             break;
 
+            case 'G': {
+                // would use atol if not for the multiplier
+                char *cp = optarg;
+                setLogSize = 0;
+                while (('0' <= *cp) && (*cp <= '9')) {
+                    setLogSize *= 10;
+                    setLogSize += *cp - '0';
+                    ++cp;
+                }
+
+                switch(*cp) {
+                case 'g':
+                case 'G':
+                    setLogSize *= 1024;
+                /* FALLTHRU */
+                case 'm':
+                case 'M':
+                    setLogSize *= 1024;
+                /* FALLTHRU */
+                case 'k':
+                case 'K':
+                    setLogSize *= 1024;
+                /* FALLTHRU */
+                case '\0':
+                break;
+
+                default:
+                    setLogSize = 0;
+                }
+
+                if (!setLogSize) {
+                    fprintf(stderr, "ERROR: -G <num><multiplier>\n");
+                    exit(1);
+                }
+            }
+            break;
+
+            case 'p':
+                getPruneList = 1;
+            break;
+
+            case 'P':
+                setPruneList = optarg;
+            break;
+
             case 'b': {
+                if (strcmp(optarg, "all") == 0) {
+                    while (devices) {
+                        dev = devices;
+                        devices = dev->next;
+                        delete dev;
+                    }
+
+                    dev = devices = new log_device_t("main", false, 'm');
+                    android::g_devCount = 1;
+                    if (android_name_to_log_id("system") == LOG_ID_SYSTEM) {
+                        dev->next = new log_device_t("system", false, 's');
+                        if (dev->next) {
+                            dev = dev->next;
+                            android::g_devCount++;
+                        }
+                    }
+                    if (android_name_to_log_id("radio") == LOG_ID_RADIO) {
+                        dev->next = new log_device_t("radio", false, 'r');
+                        if (dev->next) {
+                            dev = dev->next;
+                            android::g_devCount++;
+                        }
+                    }
+                    if (android_name_to_log_id("events") == LOG_ID_EVENTS) {
+                        dev->next = new log_device_t("events", true, 'e');
+                        if (dev->next) {
+                            dev = dev->next;
+                            android::g_devCount++;
+                            needBinary = true;
+                        }
+                    }
+                    if (android_name_to_log_id("crash") == LOG_ID_CRASH) {
+                        dev->next = new log_device_t("crash", false, 'c');
+                        if (dev->next) {
+                            android::g_devCount++;
+                        }
+                    }
+                    break;
+                }
+
                 bool binary = strcmp(optarg, "events") == 0;
                 if (binary) {
                     needBinary = true;
@@ -370,9 +513,6 @@
                     android::g_logRotateSizeKBytes
                                 = DEFAULT_LOG_ROTATE_SIZE_KBYTES;
                 } else {
-                    long logRotateSize;
-                    char *lastDigit;
-
                     if (!isdigit(optarg[0])) {
                         fprintf(stderr,"Invalid parameter to -r\n");
                         android::show_help(argv[0]);
@@ -470,6 +610,10 @@
                 }
                 break;
 
+            case 'S':
+                printStatistics = 1;
+                break;
+
             default:
                 fprintf(stderr,"Unrecognized Option\n");
                 android::show_help(argv[0]);
@@ -479,10 +623,14 @@
     }
 
     if (!devices) {
-        devices = new log_device_t("main", false, 'm');
+        dev = devices = new log_device_t("main", false, 'm');
         android::g_devCount = 1;
         if (android_name_to_log_id("system") == LOG_ID_SYSTEM) {
-            devices->next = new log_device_t("system", false, 's');
+            dev = dev->next = new log_device_t("system", false, 's');
+            android::g_devCount++;
+        }
+        if (android_name_to_log_id("crash") == LOG_ID_CRASH) {
+            dev = dev->next = new log_device_t("crash", false, 'c');
             android::g_devCount++;
         }
     }
@@ -544,7 +692,11 @@
     }
 
     dev = devices;
-    logger_list = android_logger_list_alloc(mode, tail_lines, 0);
+    if (tail_time != log_time::EPOCH) {
+        logger_list = android_logger_list_alloc_time(mode, tail_time, 0);
+    } else {
+        logger_list = android_logger_list_alloc(mode, tail_lines, 0);
+    }
     while (dev) {
         dev->logger_list = logger_list;
         dev->logger = android_logger_open(logger_list,
@@ -558,38 +710,117 @@
             int ret;
             ret = android_logger_clear(dev->logger);
             if (ret) {
-                perror("clearLog");
+                perror("failed to clear the log");
                 exit(EXIT_FAILURE);
             }
         }
 
+        if (setLogSize && android_logger_set_log_size(dev->logger, setLogSize)) {
+            perror("failed to set the log size");
+            exit(EXIT_FAILURE);
+        }
+
         if (getLogSize) {
-            int size, readable;
+            long size, readable;
 
             size = android_logger_get_log_size(dev->logger);
             if (size < 0) {
-                perror("getLogSize");
+                perror("failed to get the log size");
                 exit(EXIT_FAILURE);
             }
 
             readable = android_logger_get_log_readable_size(dev->logger);
             if (readable < 0) {
-                perror("getLogReadableSize");
+                perror("failed to get the readable log size");
                 exit(EXIT_FAILURE);
             }
 
-            printf("%s: ring buffer is %dKb (%dKb consumed), "
+            printf("%s: ring buffer is %ld%sb (%ld%sb consumed), "
                    "max entry is %db, max payload is %db\n", dev->device,
-                   size / 1024, readable / 1024,
+                   value_of_size(size), multiplier_of_size(size),
+                   value_of_size(readable), multiplier_of_size(readable),
                    (int) LOGGER_ENTRY_MAX_LEN, (int) LOGGER_ENTRY_MAX_PAYLOAD);
         }
 
         dev = dev->next;
     }
 
+    if (setPruneList) {
+        size_t len = strlen(setPruneList) + 32; // margin to allow rc
+        char *buf = (char *) malloc(len);
+
+        strcpy(buf, setPruneList);
+        int ret = android_logger_set_prune_list(logger_list, buf, len);
+        free(buf);
+
+        if (ret) {
+            perror("failed to set the prune list");
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    if (printStatistics || getPruneList) {
+        size_t len = 8192;
+        char *buf;
+
+        for(int retry = 32;
+                (retry >= 0) && ((buf = new char [len]));
+                delete [] buf, --retry) {
+            if (getPruneList) {
+                android_logger_get_prune_list(logger_list, buf, len);
+            } else {
+                android_logger_get_statistics(logger_list, buf, len);
+            }
+            buf[len-1] = '\0';
+            size_t ret = atol(buf) + 1;
+            if (ret < 4) {
+                delete [] buf;
+                buf = NULL;
+                break;
+            }
+            bool check = ret <= len;
+            len = ret;
+            if (check) {
+                break;
+            }
+        }
+
+        if (!buf) {
+            perror("failed to read data");
+            exit(EXIT_FAILURE);
+        }
+
+        // remove trailing FF
+        char *cp = buf + len - 1;
+        *cp = '\0';
+        bool truncated = *--cp != '\f';
+        if (!truncated) {
+            *cp = '\0';
+        }
+
+        // squash out the byte count
+        cp = buf;
+        if (!truncated) {
+            while (isdigit(*cp)) {
+                ++cp;
+            }
+            if (*cp == '\n') {
+                ++cp;
+            }
+        }
+
+        printf("%s", cp);
+        delete [] buf;
+        exit(0);
+    }
+
+
     if (getLogSize) {
         exit(0);
     }
+    if (setLogSize || setPruneList) {
+        exit(0);
+    }
     if (clearLog) {
         exit(0);
     }
@@ -623,7 +854,7 @@
                 fprintf(stderr, "read: unexpected length.\n");
                 exit(EXIT_FAILURE);
             }
-            perror("logcat read");
+            perror("logcat read failure");
             exit(EXIT_FAILURE);
         }
 
diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk
index bdaec14..015a23d 100644
--- a/logcat/tests/Android.mk
+++ b/logcat/tests/Android.mk
@@ -16,11 +16,7 @@
 
 LOCAL_PATH := $(call my-dir)
 
-# -----------------------------------------------------------------------------
-# Unit tests.
-# -----------------------------------------------------------------------------
-
-test_module := logcat-unit-tests
+test_module_prefix := logcat-
 test_tags := tests
 
 test_c_flags := \
@@ -29,6 +25,28 @@
     -Wall -Wextra \
     -Werror \
     -fno-builtin \
+    -std=gnu++11
+
+# -----------------------------------------------------------------------------
+# Benchmarks (actually a gTest where the result code does not matter)
+# ----------------------------------------------------------------------------
+
+benchmark_src_files := \
+    logcat_benchmark.cpp
+
+# Build benchmarks for the device. Run with:
+#   adb shell /data/nativetest/logcat-benchmarks/logcat-benchmarks
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(test_module_prefix)benchmarks
+LOCAL_MODULE_TAGS := $(test_tags)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_CFLAGS += $(test_c_flags)
+LOCAL_SRC_FILES := $(benchmark_src_files)
+include $(BUILD_NATIVE_TEST)
+
+# -----------------------------------------------------------------------------
+# Unit tests.
+# -----------------------------------------------------------------------------
 
 test_src_files := \
     logcat_test.cpp \
@@ -36,11 +54,10 @@
 # Build tests for the device (with .so). Run with:
 #   adb shell /data/nativetest/logcat-unit-tests/logcat-unit-tests
 include $(CLEAR_VARS)
-LOCAL_MODULE := $(test_module)
+LOCAL_MODULE := $(test_module_prefix)unit-tests
 LOCAL_MODULE_TAGS := $(test_tags)
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += $(test_c_flags)
-LOCAL_LDLIBS := -lpthread
 LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_SRC_FILES := $(test_src_files)
 include $(BUILD_NATIVE_TEST)
diff --git a/logcat/tests/logcat_benchmark.cpp b/logcat/tests/logcat_benchmark.cpp
new file mode 100644
index 0000000..be815be
--- /dev/null
+++ b/logcat/tests/logcat_benchmark.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2013-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gtest/gtest.h>
+
+static const char begin[] = "--------- beginning of ";
+
+TEST(logcat, sorted_order) {
+    FILE *fp;
+
+    ASSERT_TRUE(NULL != (fp = popen(
+      "logcat -v time -b radio -b events -b system -b main -d 2>/dev/null",
+      "r")));
+
+    class timestamp {
+    private:
+        int month;
+        int day;
+        int hour;
+        int minute;
+        int second;
+        int millisecond;
+        bool ok;
+
+    public:
+        void init(const char *buffer)
+        {
+            ok = false;
+            if (buffer != NULL) {
+                ok = sscanf(buffer, "%d-%d %d:%d:%d.%d ",
+                    &month, &day, &hour, &minute, &second, &millisecond) == 6;
+            }
+        }
+
+        timestamp(const char *buffer)
+        {
+            init(buffer);
+        }
+
+        bool operator< (timestamp &T)
+        {
+            return !ok || !T.ok
+             || (month < T.month)
+             || ((month == T.month)
+              && ((day < T.day)
+               || ((day == T.day)
+                && ((hour < T.hour)
+                 || ((hour == T.hour)
+                  && ((minute < T.minute)
+                   || ((minute == T.minute)
+                    && ((second < T.second)
+                     || ((second == T.second)
+                      && (millisecond < T.millisecond))))))))));
+        }
+
+        bool valid(void)
+        {
+            return ok;
+        }
+    } last(NULL);
+
+    char *last_buffer = NULL;
+    char buffer[5120];
+
+    int count = 0;
+    int next_lt_last = 0;
+
+    while (fgets(buffer, sizeof(buffer), fp)) {
+        if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
+            continue;
+        }
+        if (!last.valid()) {
+            free(last_buffer);
+            last_buffer = strdup(buffer);
+            last.init(buffer);
+        }
+        timestamp next(buffer);
+        if (next < last) {
+            if (last_buffer) {
+                fprintf(stderr, "<%s", last_buffer);
+            }
+            fprintf(stderr, ">%s", buffer);
+            ++next_lt_last;
+        }
+        if (next.valid()) {
+            free(last_buffer);
+            last_buffer = strdup(buffer);
+            last.init(buffer);
+        }
+        ++count;
+    }
+    free(last_buffer);
+
+    pclose(fp);
+
+    static const int max_ok = 2;
+
+    // Allow few fails, happens with readers active
+    fprintf(stderr, "%s: %d/%d out of order entries\n",
+            (next_lt_last)
+                ? ((next_lt_last <= max_ok)
+                    ? "WARNING"
+                    : "ERROR")
+                : "INFO",
+            next_lt_last, count);
+
+    EXPECT_GE(max_ok, next_lt_last);
+
+    // sample statistically too small
+    EXPECT_LT(100, count);
+}
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index f963a3a..9b316d1 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -14,8 +14,12 @@
  * limitations under the License.
  */
 
+#include <ctype.h>
 #include <signal.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
 #include <gtest/gtest.h>
 #include <log/log.h>
 #include <log/logger.h>
@@ -38,88 +42,10 @@
 
 static const char begin[] = "--------- beginning of ";
 
-TEST(logcat, sorted_order) {
-    FILE *fp;
-
-    ASSERT_EQ(0, NULL == (fp = popen(
-      "logcat -v time -b radio -b events -b system -b main -d 2>/dev/null",
-      "r")));
-
-    class timestamp {
-    private:
-        int month;
-        int day;
-        int hour;
-        int minute;
-        int second;
-        int millisecond;
-        bool ok;
-
-    public:
-        void init(const char *buffer)
-        {
-            ok = false;
-            if (buffer != NULL) {
-                ok = sscanf(buffer, "%d-%d %d:%d:%d.%d ",
-                    &month, &day, &hour, &minute, &second, &millisecond) == 6;
-            }
-        }
-
-        timestamp(const char *buffer)
-        {
-            init(buffer);
-        }
-
-        bool operator< (timestamp &T)
-        {
-            return !ok || !T.ok
-             || (month < T.month)
-             || ((month == T.month)
-              && ((day < T.day)
-               || ((day == T.day)
-                && ((hour < T.hour)
-                 || ((hour == T.hour)
-                  && ((minute < T.minute)
-                   || ((minute == T.minute)
-                    && ((second < T.second)
-                     || ((second == T.second)
-                      && (millisecond < T.millisecond))))))))));
-        }
-
-        bool valid(void)
-        {
-            return ok;
-        }
-    } last(NULL);
-
-    char buffer[5120];
-
-    int count = 0;
-
-    while (fgets(buffer, sizeof(buffer), fp)) {
-        if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
-            continue;
-        }
-        if (!last.valid()) {
-            last.init(buffer);
-        }
-        timestamp next(buffer);
-        ASSERT_EQ(0, next < last);
-        if (next.valid()) {
-            last.init(buffer);
-        }
-        ++count;
-    }
-
-    pclose(fp);
-
-    ASSERT_LT(100, count);
-}
-
 TEST(logcat, buckets) {
     FILE *fp;
 
-    ASSERT_EQ(0, NULL == (fp = popen(
+    ASSERT_TRUE(NULL != (fp = popen(
       "logcat -b radio -b events -b system -b main -d 2>/dev/null",
       "r")));
 
@@ -141,15 +67,15 @@
 
     pclose(fp);
 
-    ASSERT_EQ(15, ids);
+    EXPECT_EQ(15, ids);
 
-    ASSERT_EQ(4, count);
+    EXPECT_EQ(4, count);
 }
 
 TEST(logcat, tail_3) {
     FILE *fp;
 
-    ASSERT_EQ(0, NULL == (fp = popen(
+    ASSERT_TRUE(NULL != (fp = popen(
       "logcat -v long -b radio -b events -b system -b main -t 3 2>/dev/null",
       "r")));
 
@@ -173,7 +99,7 @@
 TEST(logcat, tail_10) {
     FILE *fp;
 
-    ASSERT_EQ(0, NULL == (fp = popen(
+    ASSERT_TRUE(NULL != (fp = popen(
       "logcat -v long -b radio -b events -b system -b main -t 10 2>/dev/null",
       "r")));
 
@@ -197,7 +123,7 @@
 TEST(logcat, tail_100) {
     FILE *fp;
 
-    ASSERT_EQ(0, NULL == (fp = popen(
+    ASSERT_TRUE(NULL != (fp = popen(
       "logcat -v long -b radio -b events -b system -b main -t 100 2>/dev/null",
       "r")));
 
@@ -221,7 +147,7 @@
 TEST(logcat, tail_1000) {
     FILE *fp;
 
-    ASSERT_EQ(0, NULL == (fp = popen(
+    ASSERT_TRUE(NULL != (fp = popen(
       "logcat -v long -b radio -b events -b system -b main -t 1000 2>/dev/null",
       "r")));
 
@@ -242,6 +168,72 @@
     ASSERT_EQ(1000, count);
 }
 
+TEST(logcat, tail_time) {
+    FILE *fp;
+
+    ASSERT_TRUE(NULL != (fp = popen("logcat -v long -b all -t 10 2>&1", "r")));
+
+    char buffer[5120];
+    char *last_timestamp = NULL;
+    char *first_timestamp = NULL;
+    int count = 0;
+    const unsigned int time_length = 18;
+    const unsigned int time_offset = 2;
+
+    while (fgets(buffer, sizeof(buffer), fp)) {
+        if ((buffer[0] == '[') && (buffer[1] == ' ')
+         && isdigit(buffer[time_offset]) && isdigit(buffer[time_offset + 1])
+         && (buffer[time_offset + 2] == '-')) {
+            ++count;
+            buffer[time_length + time_offset] = '\0';
+            if (!first_timestamp) {
+                first_timestamp = strdup(buffer + time_offset);
+            }
+            free(last_timestamp);
+            last_timestamp = strdup(buffer + time_offset);
+        }
+    }
+    pclose(fp);
+
+    EXPECT_EQ(10, count);
+    EXPECT_TRUE(last_timestamp != NULL);
+    EXPECT_TRUE(first_timestamp != NULL);
+
+    snprintf(buffer, sizeof(buffer), "logcat -v long -b all -t '%s' 2>&1",
+             first_timestamp);
+    ASSERT_TRUE(NULL != (fp = popen(buffer, "r")));
+
+    int second_count = 0;
+    int last_timestamp_count = -1;
+
+    while (fgets(buffer, sizeof(buffer), fp)) {
+        if ((buffer[0] == '[') && (buffer[1] == ' ')
+         && isdigit(buffer[time_offset]) && isdigit(buffer[time_offset + 1])
+         && (buffer[time_offset + 2] == '-')) {
+            ++second_count;
+            buffer[time_length + time_offset] = '\0';
+            if (first_timestamp) {
+                // we can get a transitory *extremely* rare failure if hidden
+                // underneath the time is *exactly* XX-XX XX:XX:XX.XXX000000
+                EXPECT_STREQ(buffer + time_offset, first_timestamp);
+                free(first_timestamp);
+                first_timestamp = NULL;
+            }
+            if (!strcmp(buffer + time_offset, last_timestamp)) {
+                last_timestamp_count = second_count;
+            }
+        }
+    }
+    pclose(fp);
+
+    free(last_timestamp);
+    last_timestamp = NULL;
+
+    EXPECT_TRUE(first_timestamp == NULL);
+    EXPECT_LE(count, second_count);
+    EXPECT_LE(count, last_timestamp_count);
+}
+
 TEST(logcat, End_to_End) {
     pid_t pid = getpid();
 
@@ -250,7 +242,7 @@
     ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
 
     FILE *fp;
-    ASSERT_EQ(0, NULL == (fp = popen(
+    ASSERT_TRUE(NULL != (fp = popen(
       "logcat -b events -t 100 2>/dev/null",
       "r")));
 
@@ -278,10 +270,11 @@
     ASSERT_EQ(1, count);
 }
 
-TEST(logcat, get_) {
+TEST(logcat, get_size) {
     FILE *fp;
 
-    ASSERT_EQ(0, NULL == (fp = popen(
+    // NB: crash log only available in user space
+    ASSERT_TRUE(NULL != (fp = popen(
       "logcat -b radio -b events -b system -b main -g 2>/dev/null",
       "r")));
 
@@ -291,13 +284,49 @@
 
     while (fgets(buffer, sizeof(buffer), fp)) {
         int size, consumed, max, payload;
+        char size_mult, consumed_mult;
+        long full_size, full_consumed;
 
         size = consumed = max = payload = 0;
-        if ((4 == sscanf(buffer, "%*s ring buffer is %dKb (%dKb consumed),"
-                                 " max entry is %db, max payload is %db",
-                                 &size, &consumed, &max, &payload))
-         && ((size * 3) >= consumed)
-         && ((size * 1024) > max)
+        // NB: crash log can be very small, not hit a Kb of consumed space
+        //     doubly lucky we are not including it.
+        if (6 != sscanf(buffer, "%*s ring buffer is %d%cb (%d%cb consumed),"
+                                " max entry is %db, max payload is %db",
+                                &size, &size_mult, &consumed, &consumed_mult,
+                                &max, &payload)) {
+            fprintf(stderr, "WARNING: Parse error: %s", buffer);
+            continue;
+        }
+        full_size = size;
+        switch(size_mult) {
+        case 'G':
+            full_size *= 1024;
+            /* FALLTHRU */
+        case 'M':
+            full_size *= 1024;
+            /* FALLTHRU */
+        case 'K':
+            full_size *= 1024;
+            break;
+        }
+        full_consumed = consumed;
+        switch(consumed_mult) {
+        case 'G':
+            full_consumed *= 1024;
+            /* FALLTHRU */
+        case 'M':
+            full_consumed *= 1024;
+            /* FALLTHRU */
+        case 'K':
+            full_consumed *= 1024;
+            break;
+        }
+        EXPECT_GT((full_size * 9) / 4, full_consumed);
+        EXPECT_GT(full_size, max);
+        EXPECT_GT(max, payload);
+
+        if ((((full_size * 9) / 4) >= full_consumed)
+         && (full_size > max)
          && (max > payload)) {
             ++count;
         }
@@ -308,7 +337,7 @@
     ASSERT_EQ(4, count);
 }
 
-static void caught_blocking(int signum)
+static void caught_blocking(int /*signum*/)
 {
     unsigned long long v = 0xDEADBEEFA55A0000ULL;
 
@@ -319,13 +348,17 @@
 
 TEST(logcat, blocking) {
     FILE *fp;
-    unsigned long long v = 0xDEADBEEFA55A0000ULL;
+    unsigned long long v = 0xDEADBEEFA55F0000ULL;
 
     pid_t pid = getpid();
 
     v += pid & 0xFFFF;
 
-    ASSERT_EQ(0, NULL == (fp = popen(
+    LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
+
+    v &= 0xFFFFFFFFFFFAFFFFULL;
+
+    ASSERT_TRUE(NULL != (fp = popen(
       "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
       " logcat -b events 2>&1",
       "r")));
@@ -339,14 +372,13 @@
     signal(SIGALRM, caught_blocking);
     alarm(2);
     while (fgets(buffer, sizeof(buffer), fp)) {
-        alarm(2);
-
-        ++count;
 
         if (!strncmp(buffer, "DONE", 4)) {
             break;
         }
 
+        ++count;
+
         int p;
         unsigned long long l;
 
@@ -369,12 +401,12 @@
 
     pclose(fp);
 
-    ASSERT_LT(10, count);
+    EXPECT_LE(2, count);
 
-    ASSERT_EQ(1, signals);
+    EXPECT_EQ(1, signals);
 }
 
-static void caught_blocking_tail(int signum)
+static void caught_blocking_tail(int /*signum*/)
 {
     unsigned long long v = 0xA55ADEADBEEF0000ULL;
 
@@ -385,13 +417,17 @@
 
 TEST(logcat, blocking_tail) {
     FILE *fp;
-    unsigned long long v = 0xA55ADEADBEEF0000ULL;
+    unsigned long long v = 0xA55FDEADBEEF0000ULL;
 
     pid_t pid = getpid();
 
     v += pid & 0xFFFF;
 
-    ASSERT_EQ(0, NULL == (fp = popen(
+    LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
+
+    v &= 0xFFFAFFFFFFFFFFFFULL;
+
+    ASSERT_TRUE(NULL != (fp = popen(
       "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
       " logcat -b events -T 5 2>&1",
       "r")));
@@ -405,14 +441,13 @@
     signal(SIGALRM, caught_blocking_tail);
     alarm(2);
     while (fgets(buffer, sizeof(buffer), fp)) {
-        alarm(2);
-
-        ++count;
 
         if (!strncmp(buffer, "DONE", 4)) {
             break;
         }
 
+        ++count;
+
         int p;
         unsigned long long l;
 
@@ -431,13 +466,186 @@
     alarm(0);
     signal(SIGALRM, SIG_DFL);
 
-    /* Generate SIGPIPE */
+    // Generate SIGPIPE
     fclose(fp);
     caught_blocking_tail(0);
 
     pclose(fp);
 
-    ASSERT_LT(5, count);
+    EXPECT_LE(2, count);
 
-    ASSERT_EQ(1, signals);
+    EXPECT_EQ(1, signals);
+}
+
+static void caught_blocking_clear(int /*signum*/)
+{
+    unsigned long long v = 0xDEADBEEFA55C0000ULL;
+
+    v += getpid() & 0xFFFF;
+
+    LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
+}
+
+TEST(logcat, blocking_clear) {
+    FILE *fp;
+    unsigned long long v = 0xDEADBEEFA55C0000ULL;
+
+    pid_t pid = getpid();
+
+    v += pid & 0xFFFF;
+
+    // This test is racey; an event occurs between clear and dump.
+    // We accept that we will get a false positive, but never a false negative.
+    ASSERT_TRUE(NULL != (fp = popen(
+      "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
+      " logcat -b events -c 2>&1 ;"
+      " logcat -b events 2>&1",
+      "r")));
+
+    char buffer[5120];
+
+    int count = 0;
+
+    int signals = 0;
+
+    signal(SIGALRM, caught_blocking_clear);
+    alarm(2);
+    while (fgets(buffer, sizeof(buffer), fp)) {
+
+        if (!strncmp(buffer, "clearLog: ", 10)) {
+            fprintf(stderr, "WARNING: Test lacks permission to run :-(\n");
+            count = signals = 1;
+            break;
+        }
+
+        if (!strncmp(buffer, "DONE", 4)) {
+            break;
+        }
+
+        ++count;
+
+        int p;
+        unsigned long long l;
+
+        if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l))
+         || (p != pid)) {
+            continue;
+        }
+
+        if (l == v) {
+            if (count > 1) {
+                fprintf(stderr, "WARNING: Possible false positive\n");
+            }
+            ++signals;
+            break;
+        }
+    }
+    alarm(0);
+    signal(SIGALRM, SIG_DFL);
+
+    // Generate SIGPIPE
+    fclose(fp);
+    caught_blocking_clear(0);
+
+    pclose(fp);
+
+    EXPECT_LE(1, count);
+
+    EXPECT_EQ(1, signals);
+}
+
+static bool get_white_black(char **list) {
+    FILE *fp;
+
+    fp = popen("logcat -p 2>/dev/null", "r");
+    if (fp == NULL) {
+        fprintf(stderr, "ERROR: logcat -p 2>/dev/null\n");
+        return false;
+    }
+
+    char buffer[5120];
+
+    while (fgets(buffer, sizeof(buffer), fp)) {
+        char *hold = *list;
+        char *buf = buffer;
+	while (isspace(*buf)) {
+            ++buf;
+        }
+        char *end = buf + strlen(buf);
+        while (isspace(*--end) && (end >= buf)) {
+            *end = '\0';
+        }
+        if (end < buf) {
+            continue;
+        }
+        if (hold) {
+            asprintf(list, "%s %s", hold, buf);
+            free(hold);
+        } else {
+            asprintf(list, "%s", buf);
+        }
+    }
+    pclose(fp);
+    return *list != NULL;
+}
+
+static bool set_white_black(const char *list) {
+    FILE *fp;
+
+    char buffer[5120];
+
+    snprintf(buffer, sizeof(buffer), "logcat -P '%s' 2>&1", list ? list : "");
+    fp = popen(buffer, "r");
+    if (fp == NULL) {
+        fprintf(stderr, "ERROR: %s\n", buffer);
+        return false;
+    }
+
+    while (fgets(buffer, sizeof(buffer), fp)) {
+        char *buf = buffer;
+	while (isspace(*buf)) {
+            ++buf;
+        }
+        char *end = buf + strlen(buf);
+        while ((end > buf) && isspace(*--end)) {
+            *end = '\0';
+        }
+        if (end <= buf) {
+            continue;
+        }
+        fprintf(stderr, "%s\n", buf);
+        pclose(fp);
+        return false;
+    }
+    return pclose(fp) == 0;
+}
+
+TEST(logcat, white_black_adjust) {
+    char *list = NULL;
+    char *adjust = NULL;
+
+    get_white_black(&list);
+
+    static const char adjustment[] = "~! 300/20 300/25 2000 ~1000/5 ~1000/30";
+    ASSERT_EQ(true, set_white_black(adjustment));
+    ASSERT_EQ(true, get_white_black(&adjust));
+    EXPECT_STREQ(adjustment, adjust);
+    free(adjust);
+    adjust = NULL;
+
+    static const char adjustment2[] = "300/20 300/21 2000 ~1000";
+    ASSERT_EQ(true, set_white_black(adjustment2));
+    ASSERT_EQ(true, get_white_black(&adjust));
+    EXPECT_STREQ(adjustment2, adjust);
+    free(adjust);
+    adjust = NULL;
+
+    ASSERT_EQ(true, set_white_black(list));
+    get_white_black(&adjust);
+    EXPECT_STREQ(list ? list : "", adjust ? adjust : "");
+    free(adjust);
+    adjust = NULL;
+
+    free(list);
+    list = NULL;
 }
diff --git a/logd/Android.mk b/logd/Android.mk
new file mode 100644
index 0000000..188511f
--- /dev/null
+++ b/logd/Android.mk
@@ -0,0 +1,33 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= logd
+
+LOCAL_SRC_FILES := \
+    main.cpp \
+    LogCommand.cpp \
+    CommandListener.cpp \
+    LogListener.cpp \
+    LogReader.cpp \
+    FlushCommand.cpp \
+    LogBuffer.cpp \
+    LogBufferElement.cpp \
+    LogTimes.cpp \
+    LogStatistics.cpp \
+    LogWhiteBlackList.cpp \
+    libaudit.c \
+    LogAudit.cpp \
+    event.logtags
+
+LOCAL_SHARED_LIBRARIES := \
+    libsysutils \
+    liblog \
+    libcutils \
+    libutils
+
+LOCAL_CFLAGS := -Werror $(shell sed -n 's/^\([0-9]*\)[ \t]*auditd[ \t].*/-DAUDITD_LOG_TAG=\1/p' $(LOCAL_PATH)/event.logtags)
+
+include $(BUILD_EXECUTABLE)
+
+include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
new file mode 100644
index 0000000..d7088b4
--- /dev/null
+++ b/logd/CommandListener.cpp
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2012-2014 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 <arpa/inet.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <cutils/sockets.h>
+#include <private/android_filesystem_config.h>
+#include <sysutils/SocketClient.h>
+
+#include "CommandListener.h"
+#include "LogCommand.h"
+
+CommandListener::CommandListener(LogBuffer *buf, LogReader * /*reader*/,
+                                 LogListener * /*swl*/)
+        : FrameworkListener(getLogSocket())
+        , mBuf(*buf) {
+    // registerCmd(new ShutdownCmd(buf, writer, swl));
+    registerCmd(new ClearCmd(buf));
+    registerCmd(new GetBufSizeCmd(buf));
+    registerCmd(new SetBufSizeCmd(buf));
+    registerCmd(new GetBufSizeUsedCmd(buf));
+    registerCmd(new GetStatisticsCmd(buf));
+    registerCmd(new SetPruneListCmd(buf));
+    registerCmd(new GetPruneListCmd(buf));
+}
+
+CommandListener::ShutdownCmd::ShutdownCmd(LogBuffer *buf, LogReader *reader,
+                                          LogListener *swl)
+        : LogCommand("shutdown")
+        , mBuf(*buf)
+        , mReader(*reader)
+        , mSwl(*swl)
+{ }
+
+int CommandListener::ShutdownCmd::runCommand(SocketClient * /*cli*/,
+                                             int /*argc*/,
+                                             char ** /*argv*/) {
+    mSwl.stopListener();
+    mReader.stopListener();
+    exit(0);
+}
+
+CommandListener::ClearCmd::ClearCmd(LogBuffer *buf)
+        : LogCommand("clear")
+        , mBuf(*buf)
+{ }
+
+static void setname() {
+    prctl(PR_SET_NAME, "logd.control");
+}
+
+int CommandListener::ClearCmd::runCommand(SocketClient *cli,
+                                         int argc, char **argv) {
+    setname();
+    uid_t uid = cli->getUid();
+    if (clientHasLogCredentials(cli)) {
+        uid = AID_ROOT;
+    }
+
+    if (argc < 2) {
+        cli->sendMsg("Missing Argument");
+        return 0;
+    }
+
+    int id = atoi(argv[1]);
+    if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
+        cli->sendMsg("Range Error");
+        return 0;
+    }
+
+    mBuf.clear((log_id_t) id, uid);
+    cli->sendMsg("success");
+    return 0;
+}
+
+CommandListener::GetBufSizeCmd::GetBufSizeCmd(LogBuffer *buf)
+        : LogCommand("getLogSize")
+        , mBuf(*buf)
+{ }
+
+int CommandListener::GetBufSizeCmd::runCommand(SocketClient *cli,
+                                         int argc, char **argv) {
+    setname();
+    if (argc < 2) {
+        cli->sendMsg("Missing Argument");
+        return 0;
+    }
+
+    int id = atoi(argv[1]);
+    if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
+        cli->sendMsg("Range Error");
+        return 0;
+    }
+
+    unsigned long size = mBuf.getSize((log_id_t) id);
+    char buf[512];
+    snprintf(buf, sizeof(buf), "%lu", size);
+    cli->sendMsg(buf);
+    return 0;
+}
+
+CommandListener::SetBufSizeCmd::SetBufSizeCmd(LogBuffer *buf)
+        : LogCommand("setLogSize")
+        , mBuf(*buf)
+{ }
+
+int CommandListener::SetBufSizeCmd::runCommand(SocketClient *cli,
+                                         int argc, char **argv) {
+    setname();
+    if (!clientHasLogCredentials(cli)) {
+        cli->sendMsg("Permission Denied");
+        return 0;
+    }
+
+    if (argc < 3) {
+        cli->sendMsg("Missing Argument");
+        return 0;
+    }
+
+    int id = atoi(argv[1]);
+    if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
+        cli->sendMsg("Range Error");
+        return 0;
+    }
+
+    unsigned long size = atol(argv[2]);
+    if (mBuf.setSize((log_id_t) id, size)) {
+        cli->sendMsg("Range Error");
+        return 0;
+    }
+
+    cli->sendMsg("success");
+    return 0;
+}
+
+CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer *buf)
+        : LogCommand("getLogSizeUsed")
+        , mBuf(*buf)
+{ }
+
+int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient *cli,
+                                         int argc, char **argv) {
+    setname();
+    if (argc < 2) {
+        cli->sendMsg("Missing Argument");
+        return 0;
+    }
+
+    int id = atoi(argv[1]);
+    if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
+        cli->sendMsg("Range Error");
+        return 0;
+    }
+
+    unsigned long size = mBuf.getSizeUsed((log_id_t) id);
+    char buf[512];
+    snprintf(buf, sizeof(buf), "%lu", size);
+    cli->sendMsg(buf);
+    return 0;
+}
+
+CommandListener::GetStatisticsCmd::GetStatisticsCmd(LogBuffer *buf)
+        : LogCommand("getStatistics")
+        , mBuf(*buf)
+{ }
+
+static void package_string(char **strp) {
+    const char *a = *strp;
+    if (!a) {
+        a = "";
+    }
+
+    // Calculate total buffer size prefix, count is the string length w/o nul
+    char fmt[32];
+    for(size_t l = strlen(a), y = 0, x = 6; y != x; y = x, x = strlen(fmt) - 2) {
+        snprintf(fmt, sizeof(fmt), "%zu\n%%s\n\f", l + x);
+    }
+
+    char *b = *strp;
+    *strp = NULL;
+    asprintf(strp, fmt, a);
+    free(b);
+}
+
+int CommandListener::GetStatisticsCmd::runCommand(SocketClient *cli,
+                                         int argc, char **argv) {
+    setname();
+    uid_t uid = cli->getUid();
+    if (clientHasLogCredentials(cli)) {
+        uid = AID_ROOT;
+    }
+
+    unsigned int logMask = -1;
+    if (argc > 1) {
+        logMask = 0;
+        for (int i = 1; i < argc; ++i) {
+            int id = atoi(argv[i]);
+            if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
+                cli->sendMsg("Range Error");
+                return 0;
+            }
+            logMask |= 1 << id;
+        }
+    }
+
+    char *buf = NULL;
+
+    mBuf.formatStatistics(&buf, uid, logMask);
+    if (!buf) {
+        cli->sendMsg("Failed");
+    } else {
+        package_string(&buf);
+        cli->sendMsg(buf);
+        free(buf);
+    }
+    return 0;
+}
+
+CommandListener::GetPruneListCmd::GetPruneListCmd(LogBuffer *buf)
+        : LogCommand("getPruneList")
+        , mBuf(*buf)
+{ }
+
+int CommandListener::GetPruneListCmd::runCommand(SocketClient *cli,
+                                         int /*argc*/, char ** /*argv*/) {
+    setname();
+    char *buf = NULL;
+    mBuf.formatPrune(&buf);
+    if (!buf) {
+        cli->sendMsg("Failed");
+    } else {
+        package_string(&buf);
+        cli->sendMsg(buf);
+        free(buf);
+    }
+    return 0;
+}
+
+CommandListener::SetPruneListCmd::SetPruneListCmd(LogBuffer *buf)
+        : LogCommand("setPruneList")
+        , mBuf(*buf)
+{ }
+
+int CommandListener::SetPruneListCmd::runCommand(SocketClient *cli,
+                                         int argc, char **argv) {
+    setname();
+    if (!clientHasLogCredentials(cli)) {
+        cli->sendMsg("Permission Denied");
+        return 0;
+    }
+
+    char *cp = NULL;
+    for (int i = 1; i < argc; ++i) {
+        char *p = cp;
+        if (p) {
+            cp = NULL;
+            asprintf(&cp, "%s %s", p, argv[i]);
+            free(p);
+        } else {
+            asprintf(&cp, "%s", argv[i]);
+        }
+    }
+
+    int ret = mBuf.initPrune(cp);
+    free(cp);
+
+    if (ret) {
+        cli->sendMsg("Invalid");
+        return 0;
+    }
+
+    cli->sendMsg("success");
+
+    return 0;
+}
+
+int CommandListener::getLogSocket() {
+    static const char socketName[] = "logd";
+    int sock = android_get_control_socket(socketName);
+
+    if (sock < 0) {
+        sock = socket_local_server(socketName,
+                                   ANDROID_SOCKET_NAMESPACE_RESERVED,
+                                   SOCK_STREAM);
+    }
+
+    return sock;
+}
diff --git a/logd/CommandListener.h b/logd/CommandListener.h
new file mode 100644
index 0000000..cd1c306
--- /dev/null
+++ b/logd/CommandListener.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012-2014 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 _COMMANDLISTENER_H__
+#define _COMMANDLISTENER_H__
+
+#include <sysutils/FrameworkListener.h>
+#include "LogCommand.h"
+#include "LogBuffer.h"
+#include "LogReader.h"
+#include "LogListener.h"
+
+class CommandListener : public FrameworkListener {
+    LogBuffer &mBuf;
+
+public:
+    CommandListener(LogBuffer *buf, LogReader *reader, LogListener *swl);
+    virtual ~CommandListener() {}
+
+private:
+    static int getLogSocket();
+
+    class ShutdownCmd : public LogCommand {
+        LogBuffer &mBuf;
+        LogReader &mReader;
+        LogListener &mSwl;
+
+    public:
+        ShutdownCmd(LogBuffer *buf, LogReader *reader, LogListener *swl);
+        virtual ~ShutdownCmd() {}
+        int runCommand(SocketClient *c, int argc, char ** argv);
+    };
+
+#define LogBufferCmd(name)                                       \
+    class name##Cmd : public LogCommand {                        \
+        LogBuffer &mBuf;                                         \
+    public:                                                      \
+        name##Cmd(LogBuffer *buf);                               \
+        virtual ~name##Cmd() {}                                  \
+        int runCommand(SocketClient *c, int argc, char ** argv); \
+    };
+
+    LogBufferCmd(Clear)
+    LogBufferCmd(GetBufSize)
+    LogBufferCmd(SetBufSize)
+    LogBufferCmd(GetBufSizeUsed)
+    LogBufferCmd(GetStatistics)
+    LogBufferCmd(GetPruneList)
+    LogBufferCmd(SetPruneList)
+};
+
+#endif
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
new file mode 100644
index 0000000..3be07c0
--- /dev/null
+++ b/logd/FlushCommand.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2012-2014 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>
+
+#include "FlushCommand.h"
+#include "LogBufferElement.h"
+#include "LogCommand.h"
+#include "LogReader.h"
+#include "LogTimes.h"
+
+FlushCommand::FlushCommand(LogReader &reader,
+                           bool nonBlock,
+                           unsigned long tail,
+                           unsigned int logMask,
+                           pid_t pid,
+                           log_time start)
+        : mReader(reader)
+        , mNonBlock(nonBlock)
+        , mTail(tail)
+        , mLogMask(logMask)
+        , mPid(pid)
+        , mStart(start)
+{ }
+
+// runSocketCommand is called once for every open client on the
+// log reader socket. Here we manage and associated the reader
+// client tracking and log region locks LastLogTimes list of
+// LogTimeEntrys, and spawn a transitory per-client thread to
+// work at filing data to the  socket.
+//
+// global LogTimeEntry::lock() is used to protect access,
+// reference counts are used to ensure that individual
+// LogTimeEntry lifetime is managed when not protected.
+void FlushCommand::runSocketCommand(SocketClient *client) {
+    LogTimeEntry *entry = NULL;
+    LastLogTimes &times = mReader.logbuf().mTimes;
+
+    LogTimeEntry::lock();
+    LastLogTimes::iterator it = times.begin();
+    while(it != times.end()) {
+        entry = (*it);
+        if (entry->mClient == client) {
+            entry->triggerReader_Locked();
+            if (entry->runningReader_Locked()) {
+                LogTimeEntry::unlock();
+                return;
+            }
+            entry->incRef_Locked();
+            break;
+        }
+        it++;
+    }
+
+    if (it == times.end()) {
+        // Create LogTimeEntry in notifyNewLog() ?
+        if (mTail == (unsigned long) -1) {
+            LogTimeEntry::unlock();
+            return;
+        }
+        entry = new LogTimeEntry(mReader, client, mNonBlock, mTail, mLogMask, mPid, mStart);
+        times.push_back(entry);
+    }
+
+    client->incRef();
+
+    // release client and entry reference counts once done
+    entry->startReader_Locked();
+    LogTimeEntry::unlock();
+}
+
+bool FlushCommand::hasReadLogs(SocketClient *client) {
+    return clientHasLogCredentials(client);
+}
diff --git a/logd/FlushCommand.h b/logd/FlushCommand.h
new file mode 100644
index 0000000..f34c06a
--- /dev/null
+++ b/logd/FlushCommand.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012-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 _FLUSH_COMMAND_H
+#define _FLUSH_COMMAND_H
+
+#include <log/log_read.h>
+#include <sysutils/SocketClientCommand.h>
+
+class LogBufferElement;
+
+#include "LogTimes.h"
+
+class LogReader;
+
+class FlushCommand : public SocketClientCommand {
+    LogReader &mReader;
+    bool mNonBlock;
+    unsigned long mTail;
+    unsigned int mLogMask;
+    pid_t mPid;
+    log_time mStart;
+
+public:
+    FlushCommand(LogReader &mReader,
+                 bool nonBlock = false,
+                 unsigned long tail = -1,
+                 unsigned int logMask = -1,
+                 pid_t pid = 0,
+                 log_time start = LogTimeEntry::EPOCH);
+    virtual void runSocketCommand(SocketClient *client);
+
+    static bool hasReadLogs(SocketClient *client);
+};
+
+#endif
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
new file mode 100644
index 0000000..f8d6162
--- /dev/null
+++ b/logd/LogAudit.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2014 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 <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/klog.h>
+#include <sys/prctl.h>
+#include <sys/uio.h>
+
+#include "libaudit.h"
+#include "LogAudit.h"
+
+LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmsg)
+        : SocketListener(getLogSocket(), false)
+        , logbuf(buf)
+        , reader(reader)
+        , fdDmesg(-1) {
+    logDmesg();
+    fdDmesg = fdDmsg;
+}
+
+bool LogAudit::onDataAvailable(SocketClient *cli) {
+    prctl(PR_SET_NAME, "logd.auditd");
+
+    struct audit_message rep;
+
+    rep.nlh.nlmsg_type = 0;
+    rep.nlh.nlmsg_len = 0;
+    rep.data[0] = '\0';
+
+    if (audit_get_reply(cli->getSocket(), &rep, GET_REPLY_BLOCKING, 0) < 0) {
+        SLOGE("Failed on audit_get_reply with error: %s", strerror(errno));
+        return false;
+    }
+
+    logPrint("type=%d %.*s", rep.nlh.nlmsg_type, rep.nlh.nlmsg_len, rep.data);
+
+    return true;
+}
+
+int LogAudit::logPrint(const char *fmt, ...) {
+    if (fmt == NULL) {
+        return -EINVAL;
+    }
+
+    va_list args;
+
+    char *str = NULL;
+    va_start(args, fmt);
+    int rc = vasprintf(&str, fmt, args);
+    va_end(args);
+
+    if (rc < 0) {
+        return rc;
+    }
+
+    char *cp;
+    while ((cp = strstr(str, "  "))) {
+        memmove(cp, cp + 1, strlen(cp + 1) + 1);
+    }
+
+    if (fdDmesg >= 0) {
+        struct iovec iov[2];
+
+        iov[0].iov_base = str;
+        iov[0].iov_len = strlen(str);
+        iov[1].iov_base = const_cast<char *>("\n");
+        iov[1].iov_len = 1;
+
+        writev(fdDmesg, iov, sizeof(iov) / sizeof(iov[0]));
+    }
+
+    pid_t pid = getpid();
+    pid_t tid = gettid();
+    uid_t uid = getuid();
+    log_time now;
+
+    static const char audit_str[] = " audit(";
+    char *timeptr = strstr(str, audit_str);
+    if (timeptr
+            && ((cp = now.strptime(timeptr + sizeof(audit_str) - 1, "%s.%q")))
+            && (*cp == ':')) {
+        memcpy(timeptr + sizeof(audit_str) - 1, "0.0", 3);
+        memmove(timeptr + sizeof(audit_str) - 1 + 3, cp, strlen(cp) + 1);
+    } else {
+        now.strptime("", ""); // side effect of setting CLOCK_REALTIME
+    }
+
+    static const char pid_str[] = " pid=";
+    char *pidptr = strstr(str, pid_str);
+    if (pidptr && isdigit(pidptr[sizeof(pid_str) - 1])) {
+        cp = pidptr + sizeof(pid_str) - 1;
+        pid = 0;
+        while (isdigit(*cp)) {
+            pid = (pid * 10) + (*cp - '0');
+            ++cp;
+        }
+        tid = pid;
+        uid = logbuf->pidToUid(pid);
+        memmove(pidptr, cp, strlen(cp) + 1);
+    }
+
+    // log to events
+
+    size_t l = strlen(str);
+    size_t n = l + sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
+
+    bool notify = false;
+
+    char *newstr = reinterpret_cast<char *>(malloc(n));
+    if (!newstr) {
+        rc = -ENOMEM;
+    } else {
+        cp = newstr;
+        *cp++ = AUDITD_LOG_TAG & 0xFF;
+        *cp++ = (AUDITD_LOG_TAG >> 8) & 0xFF;
+        *cp++ = (AUDITD_LOG_TAG >> 16) & 0xFF;
+        *cp++ = (AUDITD_LOG_TAG >> 24) & 0xFF;
+        *cp++ = EVENT_TYPE_STRING;
+        *cp++ = l & 0xFF;
+        *cp++ = (l >> 8) & 0xFF;
+        *cp++ = (l >> 16) & 0xFF;
+        *cp++ = (l >> 24) & 0xFF;
+        memcpy(cp, str, l);
+
+        logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid, newstr,
+                    (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
+        free(newstr);
+
+        notify = true;
+    }
+
+    // log to main
+
+    static const char comm_str[] = " comm=\"";
+    const char *comm = strstr(str, comm_str);
+    const char *estr = str + strlen(str);
+    if (comm) {
+        estr = comm;
+        comm += sizeof(comm_str) - 1;
+    } else if (pid == getpid()) {
+        pid = tid;
+        comm = "auditd";
+    } else if (!(comm = logbuf->pidToName(pid))) {
+        comm = "unknown";
+    }
+
+    const char *ecomm = strchr(comm, '"');
+    if (ecomm) {
+        ++ecomm;
+        l = ecomm - comm;
+    } else {
+        l = strlen(comm) + 1;
+        ecomm = "";
+    }
+    n = (estr - str) + strlen(ecomm) + l + 2;
+
+    newstr = reinterpret_cast<char *>(malloc(n));
+    if (!newstr) {
+        rc = -ENOMEM;
+    } else {
+        *newstr = (strstr(str, " permissive=1")
+                || strstr(str, " policy loaded "))
+                    ? ANDROID_LOG_INFO
+                    : ANDROID_LOG_WARN;
+        strlcpy(newstr + 1, comm, l);
+        strncpy(newstr + 1 + l, str, estr - str);
+        strcpy(newstr + 1 + l + (estr - str), ecomm);
+
+        logbuf->log(LOG_ID_MAIN, now, uid, pid, tid, newstr,
+                    (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
+        free(newstr);
+
+        notify = true;
+    }
+
+    free(str);
+
+    if (notify) {
+        reader->notifyNewLog();
+    }
+
+    return rc;
+}
+
+void LogAudit::logDmesg() {
+    int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
+    if (len <= 0) {
+        return;
+    }
+
+    len++;
+    char buf[len];
+
+    int rc = klogctl(KLOG_READ_ALL, buf, len);
+
+    buf[len - 1] = '\0';
+
+    for(char *tok = buf; (rc >= 0) && ((tok = strtok(tok, "\r\n"))); tok = NULL) {
+        char *audit = strstr(tok, " audit(");
+        if (!audit) {
+            continue;
+        }
+
+        *audit++ = '\0';
+
+        char *type = strstr(tok, "type=");
+        if (type) {
+            rc = logPrint("%s %s", type, audit);
+        } else {
+            rc = logPrint("%s", audit);
+        }
+    }
+}
+
+int LogAudit::getLogSocket() {
+    int fd = audit_open();
+    if (fd < 0) {
+        return fd;
+    }
+    if (audit_set_pid(fd, getpid(), WAIT_YES) < 0) {
+        audit_close(fd);
+        fd = -1;
+    }
+    return fd;
+}
diff --git a/logd/LogAudit.h b/logd/LogAudit.h
new file mode 100644
index 0000000..111030a
--- /dev/null
+++ b/logd/LogAudit.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 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 _LOGD_LOG_AUDIT_H__
+#define _LOGD_LOG_AUDIT_H__
+
+#include <sysutils/SocketListener.h>
+#include "LogReader.h"
+
+class LogAudit : public SocketListener {
+    LogBuffer *logbuf;
+    LogReader *reader;
+    int fdDmesg;
+
+public:
+    LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg);
+
+protected:
+    virtual bool onDataAvailable(SocketClient *cli);
+
+private:
+    static int getLogSocket();
+    void logDmesg();
+    int logPrint(const char *fmt, ...)
+        __attribute__ ((__format__ (__printf__, 2, 3)));
+};
+
+#endif
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
new file mode 100644
index 0000000..cd9ea20
--- /dev/null
+++ b/logd/LogBuffer.cpp
@@ -0,0 +1,503 @@
+/*
+ * Copyright (C) 2012-2014 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 <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/user.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <cutils/properties.h>
+#include <log/logger.h>
+
+#include "LogBuffer.h"
+#include "LogReader.h"
+#include "LogStatistics.h"
+#include "LogWhiteBlackList.h"
+
+// Default
+#define LOG_BUFFER_SIZE (256 * 1024) // Tuned on a per-platform basis here?
+#define log_buffer_size(id) mMaxSize[id]
+#define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
+#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
+
+static bool valid_size(unsigned long value) {
+    if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
+        return false;
+    }
+
+    long pages = sysconf(_SC_PHYS_PAGES);
+    if (pages < 1) {
+        return true;
+    }
+
+    long pagesize = sysconf(_SC_PAGESIZE);
+    if (pagesize <= 1) {
+        pagesize = PAGE_SIZE;
+    }
+
+    // maximum memory impact a somewhat arbitrary ~3%
+    pages = (pages + 31) / 32;
+    unsigned long maximum = pages * pagesize;
+
+    if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
+        return true;
+    }
+
+    return value <= maximum;
+}
+
+static unsigned long property_get_size(const char *key) {
+    char property[PROPERTY_VALUE_MAX];
+    property_get(key, property, "");
+
+    char *cp;
+    unsigned long value = strtoul(property, &cp, 10);
+
+    switch(*cp) {
+    case 'm':
+    case 'M':
+        value *= 1024;
+    /* FALLTHRU */
+    case 'k':
+    case 'K':
+        value *= 1024;
+    /* FALLTHRU */
+    case '\0':
+        break;
+
+    default:
+        value = 0;
+    }
+
+    if (!valid_size(value)) {
+        value = 0;
+    }
+
+    return value;
+}
+
+LogBuffer::LogBuffer(LastLogTimes *times)
+        : mTimes(*times) {
+    pthread_mutex_init(&mLogElementsLock, NULL);
+    dgram_qlen_statistics = false;
+
+    static const char global_tuneable[] = "persist.logd.size"; // Settings App
+    static const char global_default[] = "ro.logd.size";       // BoardConfig.mk
+
+    unsigned long default_size = property_get_size(global_tuneable);
+    if (!default_size) {
+        default_size = property_get_size(global_default);
+    }
+
+    log_id_for_each(i) {
+        char key[PROP_NAME_MAX];
+
+        snprintf(key, sizeof(key), "%s.%s",
+                 global_tuneable, android_log_id_to_name(i));
+        unsigned long property_size = property_get_size(key);
+
+        if (!property_size) {
+            snprintf(key, sizeof(key), "%s.%s",
+                     global_default, android_log_id_to_name(i));
+            property_size = property_get_size(key);
+        }
+
+        if (!property_size) {
+            property_size = default_size;
+        }
+
+        if (!property_size) {
+            property_size = LOG_BUFFER_SIZE;
+        }
+
+        if (setSize(i, property_size)) {
+            setSize(i, LOG_BUFFER_MIN_SIZE);
+        }
+    }
+}
+
+void LogBuffer::log(log_id_t log_id, log_time realtime,
+                    uid_t uid, pid_t pid, pid_t tid,
+                    const char *msg, unsigned short len) {
+    if ((log_id >= LOG_ID_MAX) || (log_id < 0)) {
+        return;
+    }
+    LogBufferElement *elem = new LogBufferElement(log_id, realtime,
+                                                  uid, pid, tid, msg, len);
+
+    pthread_mutex_lock(&mLogElementsLock);
+
+    // Insert elements in time sorted order if possible
+    //  NB: if end is region locked, place element at end of list
+    LogBufferElementCollection::iterator it = mLogElements.end();
+    LogBufferElementCollection::iterator last = it;
+    while (--it != mLogElements.begin()) {
+        if ((*it)->getRealTime() <= realtime) {
+            // halves the peak performance, use with caution
+            if (dgram_qlen_statistics) {
+                LogBufferElementCollection::iterator ib = it;
+                unsigned short buckets, num = 1;
+                for (unsigned short i = 0; (buckets = stats.dgram_qlen(i)); ++i) {
+                    buckets -= num;
+                    num += buckets;
+                    while (buckets && (--ib != mLogElements.begin())) {
+                        --buckets;
+                    }
+                    if (buckets) {
+                        break;
+                    }
+                    stats.recordDiff(
+                        elem->getRealTime() - (*ib)->getRealTime(), i);
+                }
+            }
+            break;
+        }
+        last = it;
+    }
+
+    if (last == mLogElements.end()) {
+        mLogElements.push_back(elem);
+    } else {
+        log_time end = log_time::EPOCH;
+        bool end_set = false;
+        bool end_always = false;
+
+        LogTimeEntry::lock();
+
+        LastLogTimes::iterator t = mTimes.begin();
+        while(t != mTimes.end()) {
+            LogTimeEntry *entry = (*t);
+            if (entry->owned_Locked()) {
+                if (!entry->mNonBlock) {
+                    end_always = true;
+                    break;
+                }
+                if (!end_set || (end <= entry->mEnd)) {
+                    end = entry->mEnd;
+                    end_set = true;
+                }
+            }
+            t++;
+        }
+
+        if (end_always
+                || (end_set && (end >= (*last)->getMonotonicTime()))) {
+            mLogElements.push_back(elem);
+        } else {
+            mLogElements.insert(last,elem);
+        }
+
+        LogTimeEntry::unlock();
+    }
+
+    stats.add(len, log_id, uid, pid);
+    maybePrune(log_id);
+    pthread_mutex_unlock(&mLogElementsLock);
+}
+
+// If we're using more than 256K of memory for log entries, prune
+// at least 10% of the log entries.
+//
+// mLogElementsLock must be held when this function is called.
+void LogBuffer::maybePrune(log_id_t id) {
+    size_t sizes = stats.sizes(id);
+    if (sizes > log_buffer_size(id)) {
+        size_t sizeOver90Percent = sizes - ((log_buffer_size(id) * 9) / 10);
+        size_t elements = stats.elements(id);
+        unsigned long pruneRows = elements * sizeOver90Percent / sizes;
+        elements /= 10;
+        if (pruneRows <= elements) {
+            pruneRows = elements;
+        }
+        prune(id, pruneRows);
+    }
+}
+
+// prune "pruneRows" of type "id" from the buffer.
+//
+// mLogElementsLock must be held when this function is called.
+void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
+    LogTimeEntry *oldest = NULL;
+
+    LogTimeEntry::lock();
+
+    // Region locked?
+    LastLogTimes::iterator t = mTimes.begin();
+    while(t != mTimes.end()) {
+        LogTimeEntry *entry = (*t);
+        if (entry->owned_Locked()
+                && (!oldest || (oldest->mStart > entry->mStart))) {
+            oldest = entry;
+        }
+        t++;
+    }
+
+    LogBufferElementCollection::iterator it;
+
+    if (caller_uid != AID_ROOT) {
+        for(it = mLogElements.begin(); it != mLogElements.end();) {
+            LogBufferElement *e = *it;
+
+            if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
+                break;
+            }
+
+            if (e->getLogId() != id) {
+                ++it;
+                continue;
+            }
+
+            uid_t uid = e->getUid();
+
+            if (uid == caller_uid) {
+                it = mLogElements.erase(it);
+                unsigned short len = e->getMsgLen();
+                stats.subtract(len, id, uid, e->getPid());
+                delete e;
+                pruneRows--;
+                if (pruneRows == 0) {
+                    break;
+                }
+            } else {
+                ++it;
+            }
+        }
+        LogTimeEntry::unlock();
+        return;
+    }
+
+    // prune by worst offender by uid
+    while (pruneRows > 0) {
+        // recalculate the worst offender on every batched pass
+        uid_t worst = (uid_t) -1;
+        size_t worst_sizes = 0;
+        size_t second_worst_sizes = 0;
+
+        if ((id != LOG_ID_CRASH) && mPrune.worstUidEnabled()) {
+            LidStatistics &l = stats.id(id);
+            l.sort();
+            UidStatisticsCollection::iterator iu = l.begin();
+            if (iu != l.end()) {
+                UidStatistics *u = *iu;
+                worst = u->getUid();
+                worst_sizes = u->sizes();
+                if (++iu != l.end()) {
+                    second_worst_sizes = (*iu)->sizes();
+                }
+            }
+        }
+
+        bool kick = false;
+        for(it = mLogElements.begin(); it != mLogElements.end();) {
+            LogBufferElement *e = *it;
+
+            if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
+                break;
+            }
+
+            if (e->getLogId() != id) {
+                ++it;
+                continue;
+            }
+
+            uid_t uid = e->getUid();
+
+            if (uid == worst) {
+                it = mLogElements.erase(it);
+                unsigned short len = e->getMsgLen();
+                stats.subtract(len, id, worst, e->getPid());
+                delete e;
+                kick = true;
+                pruneRows--;
+                if ((pruneRows == 0) || (worst_sizes < second_worst_sizes)) {
+                    break;
+                }
+                worst_sizes -= len;
+            } else if (mPrune.naughty(e)) { // BlackListed
+                it = mLogElements.erase(it);
+                stats.subtract(e->getMsgLen(), id, uid, e->getPid());
+                delete e;
+                pruneRows--;
+                if (pruneRows == 0) {
+                    break;
+                }
+            } else {
+                ++it;
+            }
+        }
+
+        if (!kick || !mPrune.worstUidEnabled()) {
+            break; // the following loop will ask bad clients to skip/drop
+        }
+    }
+
+    bool whitelist = false;
+    it = mLogElements.begin();
+    while((pruneRows > 0) && (it != mLogElements.end())) {
+        LogBufferElement *e = *it;
+        if (e->getLogId() == id) {
+            if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
+                if (!whitelist) {
+                    if (stats.sizes(id) > (2 * log_buffer_size(id))) {
+                        // kick a misbehaving log reader client off the island
+                        oldest->release_Locked();
+                    } else {
+                        oldest->triggerSkip_Locked(pruneRows);
+                    }
+                }
+                break;
+            }
+
+            if (mPrune.nice(e)) { // WhiteListed
+                whitelist = true;
+                it++;
+                continue;
+            }
+
+            it = mLogElements.erase(it);
+            stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
+            delete e;
+            pruneRows--;
+        } else {
+            it++;
+        }
+    }
+
+    if (whitelist && (pruneRows > 0)) {
+        it = mLogElements.begin();
+        while((it != mLogElements.end()) && (pruneRows > 0)) {
+            LogBufferElement *e = *it;
+            if (e->getLogId() == id) {
+                if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
+                    if (stats.sizes(id) > (2 * log_buffer_size(id))) {
+                        // kick a misbehaving log reader client off the island
+                        oldest->release_Locked();
+                    } else {
+                        oldest->triggerSkip_Locked(pruneRows);
+                    }
+                    break;
+                }
+                it = mLogElements.erase(it);
+                stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
+                delete e;
+                pruneRows--;
+            } else {
+                it++;
+            }
+        }
+    }
+
+    LogTimeEntry::unlock();
+}
+
+// clear all rows of type "id" from the buffer.
+void LogBuffer::clear(log_id_t id, uid_t uid) {
+    pthread_mutex_lock(&mLogElementsLock);
+    prune(id, ULONG_MAX, uid);
+    pthread_mutex_unlock(&mLogElementsLock);
+}
+
+// get the used space associated with "id".
+unsigned long LogBuffer::getSizeUsed(log_id_t id) {
+    pthread_mutex_lock(&mLogElementsLock);
+    size_t retval = stats.sizes(id);
+    pthread_mutex_unlock(&mLogElementsLock);
+    return retval;
+}
+
+// set the total space allocated to "id"
+int LogBuffer::setSize(log_id_t id, unsigned long size) {
+    // Reasonable limits ...
+    if (!valid_size(size)) {
+        return -1;
+    }
+    pthread_mutex_lock(&mLogElementsLock);
+    log_buffer_size(id) = size;
+    pthread_mutex_unlock(&mLogElementsLock);
+    return 0;
+}
+
+// get the total space allocated to "id"
+unsigned long LogBuffer::getSize(log_id_t id) {
+    pthread_mutex_lock(&mLogElementsLock);
+    size_t retval = log_buffer_size(id);
+    pthread_mutex_unlock(&mLogElementsLock);
+    return retval;
+}
+
+log_time LogBuffer::flushTo(
+        SocketClient *reader, const log_time start, bool privileged,
+        bool (*filter)(const LogBufferElement *element, void *arg), void *arg) {
+    LogBufferElementCollection::iterator it;
+    log_time max = start;
+    uid_t uid = reader->getUid();
+
+    pthread_mutex_lock(&mLogElementsLock);
+    for (it = mLogElements.begin(); it != mLogElements.end(); ++it) {
+        LogBufferElement *element = *it;
+
+        if (!privileged && (element->getUid() != uid)) {
+            continue;
+        }
+
+        if (element->getMonotonicTime() <= start) {
+            continue;
+        }
+
+        // NB: calling out to another object with mLogElementsLock held (safe)
+        if (filter && !(*filter)(element, arg)) {
+            continue;
+        }
+
+        pthread_mutex_unlock(&mLogElementsLock);
+
+        // range locking in LastLogTimes looks after us
+        max = element->flushTo(reader);
+
+        if (max == element->FLUSH_ERROR) {
+            return max;
+        }
+
+        pthread_mutex_lock(&mLogElementsLock);
+    }
+    pthread_mutex_unlock(&mLogElementsLock);
+
+    return max;
+}
+
+void LogBuffer::formatStatistics(char **strp, uid_t uid, unsigned int logMask) {
+    log_time oldest(CLOCK_MONOTONIC);
+
+    pthread_mutex_lock(&mLogElementsLock);
+
+    // Find oldest element in the log(s)
+    LogBufferElementCollection::iterator it;
+    for (it = mLogElements.begin(); it != mLogElements.end(); ++it) {
+        LogBufferElement *element = *it;
+
+        if ((logMask & (1 << element->getLogId()))) {
+            oldest = element->getMonotonicTime();
+            break;
+        }
+    }
+
+    stats.format(strp, uid, logMask, oldest);
+
+    pthread_mutex_unlock(&mLogElementsLock);
+}
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
new file mode 100644
index 0000000..4b982a8
--- /dev/null
+++ b/logd/LogBuffer.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2012-2014 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 _LOGD_LOG_BUFFER_H__
+#define _LOGD_LOG_BUFFER_H__
+
+#include <sys/types.h>
+
+#include <log/log.h>
+#include <sysutils/SocketClient.h>
+#include <utils/List.h>
+
+#include <private/android_filesystem_config.h>
+
+#include "LogBufferElement.h"
+#include "LogTimes.h"
+#include "LogStatistics.h"
+#include "LogWhiteBlackList.h"
+
+typedef android::List<LogBufferElement *> LogBufferElementCollection;
+
+class LogBuffer {
+    LogBufferElementCollection mLogElements;
+    pthread_mutex_t mLogElementsLock;
+
+    LogStatistics stats;
+
+    bool dgram_qlen_statistics;
+
+    PruneList mPrune;
+
+    unsigned long mMaxSize[LOG_ID_MAX];
+
+public:
+    LastLogTimes &mTimes;
+
+    LogBuffer(LastLogTimes *times);
+
+    void log(log_id_t log_id, log_time realtime,
+             uid_t uid, pid_t pid, pid_t tid,
+             const char *msg, unsigned short len);
+    log_time flushTo(SocketClient *writer, const log_time start,
+                     bool privileged,
+                     bool (*filter)(const LogBufferElement *element, void *arg) = NULL,
+                     void *arg = NULL);
+
+    void clear(log_id_t id, uid_t uid = AID_ROOT);
+    unsigned long getSize(log_id_t id);
+    int setSize(log_id_t id, unsigned long size);
+    unsigned long getSizeUsed(log_id_t id);
+    // *strp uses malloc, use free to release.
+    void formatStatistics(char **strp, uid_t uid, unsigned int logMask);
+
+    void enableDgramQlenStatistics() {
+        stats.enableDgramQlenStatistics();
+        dgram_qlen_statistics = true;
+    }
+
+    int initPrune(char *cp) { return mPrune.init(cp); }
+    // *strp uses malloc, use free to release.
+    void formatPrune(char **strp) { mPrune.format(strp); }
+
+    // helper
+    char *pidToName(pid_t pid) { return stats.pidToName(pid); }
+    uid_t pidToUid(pid_t pid) { return stats.pidToUid(pid); }
+
+private:
+    void maybePrune(log_id_t id);
+    void prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT);
+
+};
+
+#endif // _LOGD_LOG_BUFFER_H__
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
new file mode 100644
index 0000000..d959ceb
--- /dev/null
+++ b/logd/LogBufferElement.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2012-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <log/logger.h>
+
+#include "LogBufferElement.h"
+#include "LogReader.h"
+
+const log_time LogBufferElement::FLUSH_ERROR((uint32_t)0, (uint32_t)0);
+
+LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime,
+                                   uid_t uid, pid_t pid, pid_t tid,
+                                   const char *msg, unsigned short len)
+        : mLogId(log_id)
+        , mUid(uid)
+        , mPid(pid)
+        , mTid(tid)
+        , mMsgLen(len)
+        , mMonotonicTime(CLOCK_MONOTONIC)
+        , mRealTime(realtime) {
+    mMsg = new char[len];
+    memcpy(mMsg, msg, len);
+}
+
+LogBufferElement::~LogBufferElement() {
+    delete [] mMsg;
+}
+
+log_time LogBufferElement::flushTo(SocketClient *reader) {
+    struct logger_entry_v3 entry;
+    memset(&entry, 0, sizeof(struct logger_entry_v3));
+    entry.hdr_size = sizeof(struct logger_entry_v3);
+    entry.len = mMsgLen;
+    entry.lid = mLogId;
+    entry.pid = mPid;
+    entry.tid = mTid;
+    entry.sec = mRealTime.tv_sec;
+    entry.nsec = mRealTime.tv_nsec;
+
+    struct iovec iovec[2];
+    iovec[0].iov_base = &entry;
+    iovec[0].iov_len = sizeof(struct logger_entry_v3);
+    iovec[1].iov_base = mMsg;
+    iovec[1].iov_len = mMsgLen;
+    if (reader->sendDatav(iovec, 2)) {
+        return FLUSH_ERROR;
+    }
+
+    return mMonotonicTime;
+}
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
new file mode 100644
index 0000000..fdca973
--- /dev/null
+++ b/logd/LogBufferElement.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2012-2014 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 _LOGD_LOG_BUFFER_ELEMENT_H__
+#define _LOGD_LOG_BUFFER_ELEMENT_H__
+
+#include <sys/types.h>
+#include <sysutils/SocketClient.h>
+#include <log/log.h>
+#include <log/log_read.h>
+
+class LogBufferElement {
+    const log_id_t mLogId;
+    const uid_t mUid;
+    const pid_t mPid;
+    const pid_t mTid;
+    char *mMsg;
+    const unsigned short mMsgLen;
+    const log_time mMonotonicTime;
+    const log_time mRealTime;
+
+public:
+    LogBufferElement(log_id_t log_id, log_time realtime,
+                     uid_t uid, pid_t pid, pid_t tid,
+                     const char *msg, unsigned short len);
+    virtual ~LogBufferElement();
+
+    log_id_t getLogId() const { return mLogId; }
+    uid_t getUid(void) const { return mUid; }
+    pid_t getPid(void) const { return mPid; }
+    pid_t getTid(void) const { return mTid; }
+    unsigned short getMsgLen() const { return mMsgLen; }
+    log_time getMonotonicTime(void) const { return mMonotonicTime; }
+    log_time getRealTime(void) const { return mRealTime; }
+
+    static const log_time FLUSH_ERROR;
+    log_time flushTo(SocketClient *writer);
+};
+
+#endif
diff --git a/logd/LogCommand.cpp b/logd/LogCommand.cpp
new file mode 100644
index 0000000..e4c138e
--- /dev/null
+++ b/logd/LogCommand.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2012-2014 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 <stdio.h>
+#include <stdlib.h>
+
+#include <private/android_filesystem_config.h>
+
+#include "LogCommand.h"
+
+LogCommand::LogCommand(const char *cmd)
+        : FrameworkCommand(cmd) {
+}
+
+// gets a list of supplementary group IDs associated with
+// the socket peer.  This is implemented by opening
+// /proc/PID/status and look for the "Group:" line.
+//
+// This function introduces races especially since status
+// can change 'shape' while reading, the net result is err
+// on lack of permission.
+//
+// Race-free alternative is to introduce pairs of sockets
+// and threads for each command and reading, one each that
+// has open permissions, and one that has restricted
+// permissions.
+
+static bool groupIsLog(char *buf) {
+    char *ptr;
+    static const char ws[] = " \n";
+    bool ret = false;
+
+    for (buf = strtok_r(buf, ws, &ptr); buf; buf = strtok_r(NULL, ws, &ptr)) {
+        errno = 0;
+        gid_t Gid = strtol(buf, NULL, 10);
+        if (errno != 0) {
+            return false;
+        }
+        if (Gid == AID_LOG) {
+            ret = true;
+        }
+    }
+    return ret;
+}
+
+bool clientHasLogCredentials(SocketClient * cli) {
+    uid_t uid = cli->getUid();
+    if (uid == AID_ROOT) {
+        return true;
+    }
+
+    gid_t gid = cli->getGid();
+    if ((gid == AID_ROOT) || (gid == AID_SYSTEM) || (gid == AID_LOG)) {
+        return true;
+    }
+
+    // FYI We will typically be here for 'adb logcat'
+    bool ret = false;
+
+    char filename[1024];
+    snprintf(filename, sizeof(filename), "/proc/%d/status", cli->getPid());
+
+    FILE *file = fopen(filename, "r");
+    if (!file) {
+        return ret;
+    }
+
+    bool foundGid = false;
+    bool foundUid = false;
+
+    char line[1024];
+    while (fgets(line, sizeof(line), file)) {
+        static const char groups_string[] = "Groups:\t";
+        static const char uid_string[] = "Uid:\t";
+        static const char gid_string[] = "Gid:\t";
+
+        if (strncmp(groups_string, line, strlen(groups_string)) == 0) {
+            ret = groupIsLog(line + strlen(groups_string));
+            if (!ret) {
+                break;
+            }
+        } else if (strncmp(uid_string, line, strlen(uid_string)) == 0) {
+            uid_t u[4] = { (uid_t) -1, (uid_t) -1, (uid_t) -1, (uid_t) -1};
+
+            sscanf(line + strlen(uid_string), "%u\t%u\t%u\t%u",
+                   &u[0], &u[1], &u[2], &u[3]);
+
+            // Protect against PID reuse by checking that the UID is the same
+            if ((uid != u[0]) || (uid != u[1]) || (uid != u[2]) || (uid != u[3])) {
+                ret = false;
+                break;
+            }
+            foundUid = true;
+        } else if (strncmp(gid_string, line, strlen(gid_string)) == 0) {
+            gid_t g[4] = { (gid_t) -1, (gid_t) -1, (gid_t) -1, (gid_t) -1};
+
+            sscanf(line + strlen(gid_string), "%u\t%u\t%u\t%u",
+                   &g[0], &g[1], &g[2], &g[3]);
+
+            // Protect against PID reuse by checking that the GID is the same
+            if ((gid != g[0]) || (gid != g[1]) || (gid != g[2]) || (gid != g[3])) {
+                ret = false;
+                break;
+            }
+            foundGid = true;
+        }
+    }
+
+    fclose(file);
+
+    if (!foundGid || !foundUid) {
+        ret = false;
+    }
+
+    return ret;
+}
diff --git a/libnl_2/cache.c b/logd/LogCommand.h
similarity index 61%
copy from libnl_2/cache.c
copy to logd/LogCommand.h
index c21974d..e3b96a2 100644
--- a/libnl_2/cache.c
+++ b/logd/LogCommand.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2012-2014 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,24 +14,18 @@
  * limitations under the License.
  */
 
-/* NOTICE: This is a clean room re-implementation of libnl */
+#ifndef _LOGD_COMMAND_H
+#define _LOGD_COMMAND_H
 
-#include "netlink/cache.h"
-#include "netlink/object.h"
+#include <sysutils/SocketClient.h>
+#include <sysutils/FrameworkCommand.h>
 
-void nl_cache_free(struct nl_cache *cache)
-{
+class LogCommand : public FrameworkCommand {
+public:
+    LogCommand(const char *cmd);
+    virtual ~LogCommand() {}
+};
 
-}
+bool clientHasLogCredentials(SocketClient * cli);
 
-void nl_cache_clear(struct nl_cache *cache)
-{
-
-}
-
-void nl_cache_remove(struct nl_object *obj)
-{
-
-}
-
-
+#endif
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
new file mode 100644
index 0000000..8186cea
--- /dev/null
+++ b/logd/LogListener.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2012-2014 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 <limits.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <cutils/sockets.h>
+#include <log/logger.h>
+
+#include "LogListener.h"
+
+LogListener::LogListener(LogBuffer *buf, LogReader *reader)
+        : SocketListener(getLogSocket(), false)
+        , logbuf(buf)
+        , reader(reader)
+{  }
+
+bool LogListener::onDataAvailable(SocketClient *cli) {
+    prctl(PR_SET_NAME, "logd.writer");
+
+    char buffer[sizeof_log_id_t + sizeof(uint16_t) + sizeof(log_time)
+        + LOGGER_ENTRY_MAX_PAYLOAD];
+    struct iovec iov = { buffer, sizeof(buffer) };
+    memset(buffer, 0, sizeof(buffer));
+
+    char control[CMSG_SPACE(sizeof(struct ucred))];
+    struct msghdr hdr = {
+        NULL,
+        0,
+        &iov,
+        1,
+        control,
+        sizeof(control),
+        0,
+    };
+
+    int socket = cli->getSocket();
+
+    ssize_t n = recvmsg(socket, &hdr, 0);
+    if (n <= (ssize_t)(sizeof_log_id_t + sizeof(uint16_t) + sizeof(log_time))) {
+        return false;
+    }
+
+    struct ucred *cred = NULL;
+
+    struct cmsghdr *cmsg = CMSG_FIRSTHDR(&hdr);
+    while (cmsg != NULL) {
+        if (cmsg->cmsg_level == SOL_SOCKET
+                && cmsg->cmsg_type  == SCM_CREDENTIALS) {
+            cred = (struct ucred *)CMSG_DATA(cmsg);
+            break;
+        }
+        cmsg = CMSG_NXTHDR(&hdr, cmsg);
+    }
+
+    if (cred == NULL) {
+        return false;
+    }
+
+    if (cred->uid == getuid()) {
+        // ignore log messages we send to ourself.
+        // Such log messages are often generated by libraries we depend on
+        // which use standard Android logging.
+        return false;
+    }
+
+    // First log element is always log_id.
+    log_id_t log_id = (log_id_t) *((typeof_log_id_t *) buffer);
+    if (log_id < 0 || log_id >= LOG_ID_MAX) {
+        return false;
+    }
+    char *msg = ((char *)buffer) + sizeof_log_id_t;
+    n -= sizeof_log_id_t;
+
+    // second element is the thread id of the caller
+    pid_t tid = (pid_t) *((uint16_t *) msg);
+    msg += sizeof(uint16_t);
+    n -= sizeof(uint16_t);
+
+    // third element is the realtime at point of caller
+    log_time realtime(msg);
+    msg += sizeof(log_time);
+    n -= sizeof(log_time);
+
+    // NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a
+    // truncated message to the logs.
+
+    logbuf->log(log_id, realtime, cred->uid, cred->pid, tid, msg,
+        ((size_t) n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
+    reader->notifyNewLog();
+
+    return true;
+}
+
+int LogListener::getLogSocket() {
+    static const char socketName[] = "logdw";
+    int sock = android_get_control_socket(socketName);
+
+    if (sock < 0) {
+        sock = socket_local_server(socketName,
+                                   ANDROID_SOCKET_NAMESPACE_RESERVED,
+                                   SOCK_DGRAM);
+    }
+
+    int on = 1;
+    if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
+        return -1;
+    }
+    return sock;
+}
diff --git a/logd/LogListener.h b/logd/LogListener.h
new file mode 100644
index 0000000..7099e13
--- /dev/null
+++ b/logd/LogListener.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012-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 _LOGD_LOG_LISTENER_H__
+#define _LOGD_LOG_LISTENER_H__
+
+#include <sysutils/SocketListener.h>
+#include "LogReader.h"
+
+class LogListener : public SocketListener {
+    LogBuffer *logbuf;
+    LogReader *reader;
+
+public:
+    LogListener(LogBuffer *buf, LogReader *reader);
+
+protected:
+    virtual bool onDataAvailable(SocketClient *cli);
+
+private:
+    static int getLogSocket();
+};
+
+#endif
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
new file mode 100644
index 0000000..8458c19
--- /dev/null
+++ b/logd/LogReader.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2012-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.
+ */
+
+#include <ctype.h>
+#include <poll.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+
+#include <cutils/sockets.h>
+
+#include "LogReader.h"
+#include "FlushCommand.h"
+
+LogReader::LogReader(LogBuffer *logbuf)
+        : SocketListener(getLogSocket(), true)
+        , mLogbuf(*logbuf)
+{ }
+
+// When we are notified a new log entry is available, inform
+// all of our listening sockets.
+void LogReader::notifyNewLog() {
+    FlushCommand command(*this);
+    runOnEachSocket(&command);
+}
+
+bool LogReader::onDataAvailable(SocketClient *cli) {
+    prctl(PR_SET_NAME, "logd.reader");
+
+    char buffer[255];
+
+    int len = read(cli->getSocket(), buffer, sizeof(buffer) - 1);
+    if (len <= 0) {
+        doSocketDelete(cli);
+        return false;
+    }
+    buffer[len] = '\0';
+
+    unsigned long tail = 0;
+    static const char _tail[] = " tail=";
+    char *cp = strstr(buffer, _tail);
+    if (cp) {
+        tail = atol(cp + sizeof(_tail) - 1);
+    }
+
+    log_time start(log_time::EPOCH);
+    static const char _start[] = " start=";
+    cp = strstr(buffer, _start);
+    if (cp) {
+        // Parse errors will result in current time
+        start.strptime(cp + sizeof(_start) - 1, "%s.%q");
+    }
+
+    unsigned int logMask = -1;
+    static const char _logIds[] = " lids=";
+    cp = strstr(buffer, _logIds);
+    if (cp) {
+        logMask = 0;
+        cp += sizeof(_logIds) - 1;
+        while (*cp && *cp != '\0') {
+            int val = 0;
+            while (isdigit(*cp)) {
+                val = val * 10 + *cp - '0';
+                ++cp;
+            }
+            logMask |= 1 << val;
+            if (*cp != ',') {
+                break;
+            }
+            ++cp;
+        }
+    }
+
+    pid_t pid = 0;
+    static const char _pid[] = " pid=";
+    cp = strstr(buffer, _pid);
+    if (cp) {
+        pid = atol(cp + sizeof(_pid) - 1);
+    }
+
+    bool nonBlock = false;
+    if (strncmp(buffer, "dumpAndClose", 12) == 0) {
+        nonBlock = true;
+    }
+
+    // Convert realtime to monotonic time
+    if (start == log_time::EPOCH) {
+        start = LogTimeEntry::EPOCH;
+    } else {
+        class LogFindStart {
+            const pid_t mPid;
+            const unsigned mLogMask;
+            bool startTimeSet;
+            log_time &start;
+            log_time last;
+
+        public:
+            LogFindStart(unsigned logMask, pid_t pid, log_time &start)
+                    : mPid(pid)
+                    , mLogMask(logMask)
+                    , startTimeSet(false)
+                    , start(start)
+                    , last(LogTimeEntry::EPOCH)
+            { }
+
+            static bool callback(const LogBufferElement *element, void *obj) {
+                LogFindStart *me = reinterpret_cast<LogFindStart *>(obj);
+                if (!me->startTimeSet
+                        && (!me->mPid || (me->mPid == element->getPid()))
+                        && (me->mLogMask & (1 << element->getLogId()))) {
+                    if (me->start == element->getRealTime()) {
+                        me->start = element->getMonotonicTime();
+                        me->startTimeSet = true;
+                    } else {
+                        if (me->start < element->getRealTime()) {
+                            me->start = me->last;
+                            me->startTimeSet = true;
+                        }
+                        me->last = element->getMonotonicTime();
+                    }
+                }
+                return false;
+            }
+
+            bool found() { return startTimeSet; }
+        } logFindStart(logMask, pid, start);
+
+        logbuf().flushTo(cli, LogTimeEntry::EPOCH,
+                         FlushCommand::hasReadLogs(cli),
+                         logFindStart.callback, &logFindStart);
+
+        if (!logFindStart.found()) {
+            if (nonBlock) {
+                doSocketDelete(cli);
+                return false;
+            }
+            log_time now(CLOCK_MONOTONIC);
+            start = now;
+        }
+    }
+
+    FlushCommand command(*this, nonBlock, tail, logMask, pid, start);
+    command.runSocketCommand(cli);
+    return true;
+}
+
+void LogReader::doSocketDelete(SocketClient *cli) {
+    LastLogTimes &times = mLogbuf.mTimes;
+    LogTimeEntry::lock();
+    LastLogTimes::iterator it = times.begin();
+    while(it != times.end()) {
+        LogTimeEntry *entry = (*it);
+        if (entry->mClient == cli) {
+            times.erase(it);
+            entry->release_Locked();
+            break;
+        }
+        it++;
+    }
+    LogTimeEntry::unlock();
+}
+
+int LogReader::getLogSocket() {
+    static const char socketName[] = "logdr";
+    int sock = android_get_control_socket(socketName);
+
+    if (sock < 0) {
+        sock = socket_local_server(socketName,
+                                   ANDROID_SOCKET_NAMESPACE_RESERVED,
+                                   SOCK_SEQPACKET);
+    }
+
+    return sock;
+}
diff --git a/logd/LogReader.h b/logd/LogReader.h
new file mode 100644
index 0000000..91559a3
--- /dev/null
+++ b/logd/LogReader.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2012-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 _LOGD_LOG_WRITER_H__
+#define _LOGD_LOG_WRITER_H__
+
+#include <sysutils/SocketListener.h>
+#include "LogBuffer.h"
+#include "LogTimes.h"
+
+class LogReader : public SocketListener {
+    LogBuffer &mLogbuf;
+
+public:
+    LogReader(LogBuffer *logbuf);
+    void notifyNewLog();
+
+    LogBuffer &logbuf(void) const { return mLogbuf; }
+
+protected:
+    virtual bool onDataAvailable(SocketClient *cli);
+
+private:
+    static int getLogSocket();
+
+    void doSocketDelete(SocketClient *cli);
+
+};
+
+#endif
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
new file mode 100644
index 0000000..81c9bab
--- /dev/null
+++ b/logd/LogStatistics.cpp
@@ -0,0 +1,926 @@
+/*
+ * Copyright (C) 2014 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 <fcntl.h>
+#include <stdarg.h>
+#include <time.h>
+
+#include <log/logger.h>
+#include <private/android_filesystem_config.h>
+#include <utils/String8.h>
+
+#include "LogStatistics.h"
+
+PidStatistics::PidStatistics(pid_t pid, char *name)
+        : pid(pid)
+        , mSizesTotal(0)
+        , mElementsTotal(0)
+        , mSizes(0)
+        , mElements(0)
+        , name(name)
+        , mGone(false)
+{ }
+
+#ifdef DO_NOT_ERROR_IF_PIDSTATISTICS_USES_A_COPY_CONSTRUCTOR
+PidStatistics::PidStatistics(const PidStatistics &copy)
+        : pid(copy->pid)
+        , name(copy->name ? strdup(copy->name) : NULL)
+        , mSizesTotal(copy->mSizesTotal)
+        , mElementsTotal(copy->mElementsTotal)
+        , mSizes(copy->mSizes)
+        , mElements(copy->mElements)
+        , mGone(copy->mGone)
+{ }
+#endif
+
+PidStatistics::~PidStatistics() {
+    free(name);
+}
+
+bool PidStatistics::pidGone() {
+    if (mGone) {
+        return true;
+    }
+    if (pid == gone) {
+        return true;
+    }
+    if (kill(pid, 0) && (errno != EPERM)) {
+        mGone = true;
+        return true;
+    }
+    return false;
+}
+
+void PidStatistics::setName(char *new_name) {
+    free(name);
+    name = new_name;
+}
+
+void PidStatistics::add(unsigned short size) {
+    mSizesTotal += size;
+    ++mElementsTotal;
+    mSizes += size;
+    ++mElements;
+}
+
+bool PidStatistics::subtract(unsigned short size) {
+    mSizes -= size;
+    --mElements;
+    return (mElements == 0) && pidGone();
+}
+
+void PidStatistics::addTotal(size_t size, size_t element) {
+    if (pid == gone) {
+        mSizesTotal += size;
+        mElementsTotal += element;
+    }
+}
+
+// must call free to release return value
+char *PidStatistics::pidToName(pid_t pid) {
+    char *retval = NULL;
+    if (pid != gone) {
+        char buffer[512];
+        snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
+        int fd = open(buffer, O_RDONLY);
+        if (fd >= 0) {
+            ssize_t ret = read(fd, buffer, sizeof(buffer));
+            if (ret > 0) {
+                buffer[sizeof(buffer)-1] = '\0';
+                // frameworks intermediate state
+                if (strcmp(buffer, "<pre-initialized>")) {
+                    retval = strdup(buffer);
+                }
+            }
+            close(fd);
+        }
+    }
+    return retval;
+}
+
+UidStatistics::UidStatistics(uid_t uid)
+        : uid(uid)
+        , mSizes(0)
+        , mElements(0) {
+    Pids.clear();
+}
+
+UidStatistics::~UidStatistics() {
+    PidStatisticsCollection::iterator it;
+    for (it = begin(); it != end();) {
+        delete (*it);
+        it = Pids.erase(it);
+    }
+}
+
+void UidStatistics::add(unsigned short size, pid_t pid) {
+    mSizes += size;
+    ++mElements;
+
+    PidStatistics *p;
+    PidStatisticsCollection::iterator last;
+    PidStatisticsCollection::iterator it;
+    for (last = it = begin(); it != end(); last = it, ++it) {
+        p = *it;
+        if (pid == p->getPid()) {
+            p->add(size);
+            return;
+        }
+    }
+    // insert if the gone entry.
+    bool insert = (last != it) && (p->getPid() == p->gone);
+    p = new PidStatistics(pid, pidToName(pid));
+    if (insert) {
+        Pids.insert(last, p);
+    } else {
+        Pids.push_back(p);
+    }
+    p->add(size);
+}
+
+void UidStatistics::subtract(unsigned short size, pid_t pid) {
+    mSizes -= size;
+    --mElements;
+
+    PidStatisticsCollection::iterator it;
+    for (it = begin(); it != end(); ++it) {
+        PidStatistics *p = *it;
+        if (pid == p->getPid()) {
+            if (p->subtract(size)) {
+                size_t szsTotal = p->sizesTotal();
+                size_t elsTotal = p->elementsTotal();
+                delete p;
+                Pids.erase(it);
+                it = end();
+                --it;
+                if (it == end()) {
+                    p = new PidStatistics(p->gone);
+                    Pids.push_back(p);
+                } else {
+                    p = *it;
+                    if (p->getPid() != p->gone) {
+                        p = new PidStatistics(p->gone);
+                        Pids.push_back(p);
+                    }
+                }
+                p->addTotal(szsTotal, elsTotal);
+            }
+            return;
+        }
+    }
+}
+
+void UidStatistics::sort() {
+    for (bool pass = true; pass;) {
+        pass = false;
+        PidStatisticsCollection::iterator it = begin();
+        if (it != end()) {
+            PidStatisticsCollection::iterator lt = it;
+            PidStatistics *l = (*lt);
+            while (++it != end()) {
+                PidStatistics *n = (*it);
+                if ((n->getPid() != n->gone) && (n->sizes() > l->sizes())) {
+                    pass = true;
+                    Pids.erase(it);
+                    Pids.insert(lt, n);
+                    it = lt;
+                    n = l;
+                }
+                lt = it;
+                l = n;
+            }
+        }
+    }
+}
+
+size_t UidStatistics::sizes(pid_t pid) {
+    if (pid == pid_all) {
+        return sizes();
+    }
+
+    PidStatisticsCollection::iterator it;
+    for (it = begin(); it != end(); ++it) {
+        PidStatistics *p = *it;
+        if (pid == p->getPid()) {
+            return p->sizes();
+        }
+    }
+    return 0;
+}
+
+size_t UidStatistics::elements(pid_t pid) {
+    if (pid == pid_all) {
+        return elements();
+    }
+
+    PidStatisticsCollection::iterator it;
+    for (it = begin(); it != end(); ++it) {
+        PidStatistics *p = *it;
+        if (pid == p->getPid()) {
+            return p->elements();
+        }
+    }
+    return 0;
+}
+
+size_t UidStatistics::sizesTotal(pid_t pid) {
+    size_t sizes = 0;
+    PidStatisticsCollection::iterator it;
+    for (it = begin(); it != end(); ++it) {
+        PidStatistics *p = *it;
+        if ((pid == pid_all) || (pid == p->getPid())) {
+            sizes += p->sizesTotal();
+        }
+    }
+    return sizes;
+}
+
+size_t UidStatistics::elementsTotal(pid_t pid) {
+    size_t elements = 0;
+    PidStatisticsCollection::iterator it;
+    for (it = begin(); it != end(); ++it) {
+        PidStatistics *p = *it;
+        if ((pid == pid_all) || (pid == p->getPid())) {
+            elements += p->elementsTotal();
+        }
+    }
+    return elements;
+}
+
+LidStatistics::LidStatistics() {
+    Uids.clear();
+}
+
+LidStatistics::~LidStatistics() {
+    UidStatisticsCollection::iterator it;
+    for (it = begin(); it != end();) {
+        delete (*it);
+        it = Uids.erase(it);
+    }
+}
+
+void LidStatistics::add(unsigned short size, uid_t uid, pid_t pid) {
+    UidStatistics *u;
+    UidStatisticsCollection::iterator it;
+    UidStatisticsCollection::iterator last;
+
+    if (uid == (uid_t) -1) { // init
+        uid = (uid_t) AID_ROOT;
+    }
+
+    for (last = it = begin(); it != end(); last = it, ++it) {
+        u = *it;
+        if (uid == u->getUid()) {
+            u->add(size, pid);
+            if ((last != it) && ((*last)->sizesTotal() < u->sizesTotal())) {
+                Uids.erase(it);
+                Uids.insert(last, u);
+            }
+            return;
+        }
+    }
+    u = new UidStatistics(uid);
+    if ((last != it) && ((*last)->sizesTotal() < (size_t) size)) {
+        Uids.insert(last, u);
+    } else {
+        Uids.push_back(u);
+    }
+    u->add(size, pid);
+}
+
+void LidStatistics::subtract(unsigned short size, uid_t uid, pid_t pid) {
+    UidStatisticsCollection::iterator it;
+    for (it = begin(); it != end(); ++it) {
+        UidStatistics *u = *it;
+        if (uid == u->getUid()) {
+            u->subtract(size, pid);
+            return;
+        }
+    }
+}
+
+void LidStatistics::sort() {
+    for (bool pass = true; pass;) {
+        pass = false;
+        UidStatisticsCollection::iterator it = begin();
+        if (it != end()) {
+            UidStatisticsCollection::iterator lt = it;
+            UidStatistics *l = (*lt);
+            while (++it != end()) {
+                UidStatistics *n = (*it);
+                if (n->sizes() > l->sizes()) {
+                    pass = true;
+                    Uids.erase(it);
+                    Uids.insert(lt, n);
+                    it = lt;
+                    n = l;
+                }
+                lt = it;
+                l = n;
+            }
+        }
+    }
+}
+
+size_t LidStatistics::sizes(uid_t uid, pid_t pid) {
+    size_t sizes = 0;
+    UidStatisticsCollection::iterator it;
+    for (it = begin(); it != end(); ++it) {
+        UidStatistics *u = *it;
+        if ((uid == uid_all) || (uid == u->getUid())) {
+            sizes += u->sizes(pid);
+        }
+    }
+    return sizes;
+}
+
+size_t LidStatistics::elements(uid_t uid, pid_t pid) {
+    size_t elements = 0;
+    UidStatisticsCollection::iterator it;
+    for (it = begin(); it != end(); ++it) {
+        UidStatistics *u = *it;
+        if ((uid == uid_all) || (uid == u->getUid())) {
+            elements += u->elements(pid);
+        }
+    }
+    return elements;
+}
+
+size_t LidStatistics::sizesTotal(uid_t uid, pid_t pid) {
+    size_t sizes = 0;
+    UidStatisticsCollection::iterator it;
+    for (it = begin(); it != end(); ++it) {
+        UidStatistics *u = *it;
+        if ((uid == uid_all) || (uid == u->getUid())) {
+            sizes += u->sizesTotal(pid);
+        }
+    }
+    return sizes;
+}
+
+size_t LidStatistics::elementsTotal(uid_t uid, pid_t pid) {
+    size_t elements = 0;
+    UidStatisticsCollection::iterator it;
+    for (it = begin(); it != end(); ++it) {
+        UidStatistics *u = *it;
+        if ((uid == uid_all) || (uid == u->getUid())) {
+            elements += u->elementsTotal(pid);
+        }
+    }
+    return elements;
+}
+
+LogStatistics::LogStatistics()
+        : start(CLOCK_MONOTONIC) {
+    log_id_for_each(i) {
+        mSizes[i] = 0;
+        mElements[i] = 0;
+    }
+
+    dgram_qlen_statistics = false;
+    for(unsigned short bucket = 0; dgram_qlen(bucket); ++bucket) {
+        mMinimum[bucket].tv_sec = mMinimum[bucket].tv_sec_max;
+        mMinimum[bucket].tv_nsec = mMinimum[bucket].tv_nsec_max;
+    }
+}
+
+//   Each bucket below represents a dgram_qlen of log messages. By
+//   finding the minimum period of time from start to finish
+//   of each dgram_qlen, we can get a performance expectation for
+//   the user space logger. The net result is that the period
+//   of time divided by the dgram_qlen will give us the average time
+//   between log messages; at the point where the average time
+//   is greater than the throughput capability of the logger
+//   we will not longer require the benefits of the FIFO formed
+//   by max_dgram_qlen. We will also expect to see a very visible
+//   knee in the average time between log messages at this point,
+//   so we do not necessarily have to compare the rate against the
+//   measured performance (BM_log_maximum_retry) of the logger.
+//
+//   for example (reformatted):
+//
+//       Minimum time between log events per dgram_qlen:
+//       1   2   3   5   10  20  30  50  100  200 300 400 500 600
+//       5u2 12u 13u 15u 16u 27u 30u 36u 407u 3m1 3m3 3m9 3m9 5m5
+//
+//   demonstrates a clear knee rising at 100, so this means that for this
+//   case max_dgram_qlen = 100 would be more than sufficient to handle the
+//   worst that the system could stuff into the logger. The
+//   BM_log_maximum_retry performance (derated by the log collection) on the
+//   same system was 33.2us so we would almost be fine with max_dgram_qlen = 50.
+//   BM_log_maxumum_retry with statistics off is roughly 20us, so
+//   max_dgram_qlen = 20 would work. We will be more than willing to have
+//   a large engineering margin so the rule of thumb that lead us to 100 is
+//   fine.
+//
+// bucket dgram_qlen are tuned for /proc/sys/net/unix/max_dgram_qlen = 300
+const unsigned short LogStatistics::mBuckets[] = {
+    1, 2, 3, 5, 10, 20, 30, 50, 100, 200, 300, 400, 500, 600
+};
+
+unsigned short LogStatistics::dgram_qlen(unsigned short bucket) {
+    if (bucket >= sizeof(mBuckets) / sizeof(mBuckets[0])) {
+        return 0;
+    }
+    return mBuckets[bucket];
+}
+
+unsigned long long LogStatistics::minimum(unsigned short bucket) {
+    if (mMinimum[bucket].tv_sec == mMinimum[bucket].tv_sec_max) {
+        return 0;
+    }
+    return mMinimum[bucket].nsec();
+}
+
+void LogStatistics::recordDiff(log_time diff, unsigned short bucket) {
+    if ((diff.tv_sec || diff.tv_nsec) && (mMinimum[bucket] > diff)) {
+        mMinimum[bucket] = diff;
+    }
+}
+
+void LogStatistics::add(unsigned short size,
+                        log_id_t log_id, uid_t uid, pid_t pid) {
+    mSizes[log_id] += size;
+    ++mElements[log_id];
+    id(log_id).add(size, uid, pid);
+}
+
+void LogStatistics::subtract(unsigned short size,
+                             log_id_t log_id, uid_t uid, pid_t pid) {
+    mSizes[log_id] -= size;
+    --mElements[log_id];
+    id(log_id).subtract(size, uid, pid);
+}
+
+size_t LogStatistics::sizes(log_id_t log_id, uid_t uid, pid_t pid) {
+    if (log_id != log_id_all) {
+        return id(log_id).sizes(uid, pid);
+    }
+    size_t sizes = 0;
+    log_id_for_each(i) {
+        sizes += id(i).sizes(uid, pid);
+    }
+    return sizes;
+}
+
+size_t LogStatistics::elements(log_id_t log_id, uid_t uid, pid_t pid) {
+    if (log_id != log_id_all) {
+        return id(log_id).elements(uid, pid);
+    }
+    size_t elements = 0;
+    log_id_for_each(i) {
+        elements += id(i).elements(uid, pid);
+    }
+    return elements;
+}
+
+size_t LogStatistics::sizesTotal(log_id_t log_id, uid_t uid, pid_t pid) {
+    if (log_id != log_id_all) {
+        return id(log_id).sizesTotal(uid, pid);
+    }
+    size_t sizes = 0;
+    log_id_for_each(i) {
+        sizes += id(i).sizesTotal(uid, pid);
+    }
+    return sizes;
+}
+
+size_t LogStatistics::elementsTotal(log_id_t log_id, uid_t uid, pid_t pid) {
+    if (log_id != log_id_all) {
+        return id(log_id).elementsTotal(uid, pid);
+    }
+    size_t elements = 0;
+    log_id_for_each(i) {
+        elements += id(i).elementsTotal(uid, pid);
+    }
+    return elements;
+}
+
+void LogStatistics::format(char **buf,
+                           uid_t uid, unsigned int logMask, log_time oldest) {
+    static const unsigned short spaces_current = 13;
+    static const unsigned short spaces_total = 19;
+
+    if (*buf) {
+        free(*buf);
+        *buf = NULL;
+    }
+
+    android::String8 string("        span -> size/num");
+    size_t oldLength;
+    short spaces = 2;
+
+    log_id_for_each(i) {
+        if (!logMask & (1 << i)) {
+            continue;
+        }
+        oldLength = string.length();
+        if (spaces < 0) {
+            spaces = 0;
+        }
+        string.appendFormat("%*s%s", spaces, "", android_log_id_to_name(i));
+        spaces += spaces_total + oldLength - string.length();
+
+        LidStatistics &l = id(i);
+        l.sort();
+
+        UidStatisticsCollection::iterator iu;
+        for (iu = l.begin(); iu != l.end(); ++iu) {
+            (*iu)->sort();
+        }
+    }
+
+    spaces = 1;
+    log_time t(CLOCK_MONOTONIC);
+    unsigned long long d = t.nsec() - start.nsec();
+    string.appendFormat("\nTotal%4llu:%02llu:%02llu.%09llu",
+                  d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60,
+                  (d / NS_PER_SEC) % 60, d % NS_PER_SEC);
+
+    log_id_for_each(i) {
+        if (!(logMask & (1 << i))) {
+            continue;
+        }
+        oldLength = string.length();
+        if (spaces < 0) {
+            spaces = 0;
+        }
+        string.appendFormat("%*s%zu/%zu", spaces, "",
+                            sizesTotal(i), elementsTotal(i));
+        spaces += spaces_total + oldLength - string.length();
+    }
+
+    spaces = 1;
+    d = t.nsec() - oldest.nsec();
+    string.appendFormat("\nNow%6llu:%02llu:%02llu.%09llu",
+                  d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60,
+                  (d / NS_PER_SEC) % 60, d % NS_PER_SEC);
+
+    log_id_for_each(i) {
+        if (!(logMask & (1 << i))) {
+            continue;
+        }
+
+        size_t els = elements(i);
+        if (els) {
+            oldLength = string.length();
+            if (spaces < 0) {
+                spaces = 0;
+            }
+            string.appendFormat("%*s%zu/%zu", spaces, "", sizes(i), els);
+            spaces -= string.length() - oldLength;
+        }
+        spaces += spaces_total;
+    }
+
+    // Construct list of worst spammers by Pid
+    static const unsigned char num_spammers = 10;
+    bool header = false;
+
+    log_id_for_each(i) {
+        if (!(logMask & (1 << i))) {
+            continue;
+        }
+
+        PidStatisticsCollection pids;
+        pids.clear();
+
+        LidStatistics &l = id(i);
+        UidStatisticsCollection::iterator iu;
+        for (iu = l.begin(); iu != l.end(); ++iu) {
+            UidStatistics &u = *(*iu);
+            PidStatisticsCollection::iterator ip;
+            for (ip = u.begin(); ip != u.end(); ++ip) {
+                PidStatistics *p = (*ip);
+                if (p->getPid() == p->gone) {
+                    break;
+                }
+
+                size_t mySizes = p->sizes();
+
+                PidStatisticsCollection::iterator q;
+                unsigned char num = 0;
+                for (q = pids.begin(); q != pids.end(); ++q) {
+                    if (mySizes > (*q)->sizes()) {
+                        pids.insert(q, p);
+                        break;
+                    }
+                    // do we need to traverse deeper in the list?
+                    if (++num > num_spammers) {
+                        break;
+                    }
+                }
+                if (q == pids.end()) {
+                   pids.push_back(p);
+                }
+            }
+        }
+
+        size_t threshold = sizes(i);
+        if (threshold < 65536) {
+            threshold = 65536;
+        }
+        threshold /= 100;
+
+        PidStatisticsCollection::iterator pt = pids.begin();
+
+        for(int line = 0;
+                (pt != pids.end()) && (line < num_spammers);
+                ++line, pt = pids.erase(pt)) {
+            PidStatistics *p = *pt;
+
+            size_t sizes = p->sizes();
+            if (sizes < threshold) {
+                break;
+            }
+
+            char *name = p->getName();
+            pid_t pid = p->getPid();
+            if (!name || !*name) {
+                name = pidToName(pid);
+                if (name) {
+                    if (*name) {
+                        p->setName(name);
+                    } else {
+                        free(name);
+                        name = NULL;
+                    }
+                }
+            }
+
+            if (!header) {
+                string.appendFormat("\n\nChattiest clients:\n"
+                                    "log id %-*s PID[?] name",
+                                    spaces_total, "size/total");
+                header = true;
+            }
+
+            size_t sizesTotal = p->sizesTotal();
+
+            android::String8 sz("");
+            sz.appendFormat((sizes != sizesTotal) ? "%zu/%zu" : "%zu",
+                            sizes, sizesTotal);
+
+            android::String8 pd("");
+            pd.appendFormat("%u%c", pid, p->pidGone() ? '?' : ' ');
+
+            string.appendFormat("\n%-7s%-*s %-7s%s",
+                                line ? "" : android_log_id_to_name(i),
+                                spaces_total, sz.string(), pd.string(),
+                                name ? name : "");
+        }
+
+        pids.clear();
+    }
+
+    if (dgram_qlen_statistics) {
+        const unsigned short spaces_time = 6;
+        const unsigned long long max_seconds = 100000;
+        spaces = 0;
+        string.append("\n\nMinimum time between log events per dgram_qlen:\n");
+        for(unsigned short i = 0; dgram_qlen(i); ++i) {
+            oldLength = string.length();
+            if (spaces < 0) {
+                spaces = 0;
+            }
+            string.appendFormat("%*s%u", spaces, "", dgram_qlen(i));
+            spaces += spaces_time + oldLength - string.length();
+        }
+        string.append("\n");
+        spaces = 0;
+        unsigned short n;
+        for(unsigned short i = 0; (n = dgram_qlen(i)); ++i) {
+            unsigned long long duration = minimum(i);
+            if (duration) {
+                duration /= n;
+                if (duration >= (NS_PER_SEC * max_seconds)) {
+                    duration = NS_PER_SEC * (max_seconds - 1);
+                }
+                oldLength = string.length();
+                if (spaces < 0) {
+                    spaces = 0;
+                }
+                string.appendFormat("%*s", spaces, "");
+                if (duration >= (NS_PER_SEC * 10)) {
+                    string.appendFormat("%llu",
+                        (duration + (NS_PER_SEC / 2))
+                            / NS_PER_SEC);
+                } else if (duration >= (NS_PER_SEC / (1000 / 10))) {
+                    string.appendFormat("%llum",
+                        (duration + (NS_PER_SEC / 2 / 1000))
+                            / (NS_PER_SEC / 1000));
+                } else if (duration >= (NS_PER_SEC / (1000000 / 10))) {
+                    string.appendFormat("%lluu",
+                         (duration + (NS_PER_SEC / 2 / 1000000))
+                             / (NS_PER_SEC / 1000000));
+                } else {
+                    string.appendFormat("%llun", duration);
+                }
+                spaces -= string.length() - oldLength;
+            }
+            spaces += spaces_time;
+        }
+    }
+
+    log_id_for_each(i) {
+        if (!(logMask & (1 << i))) {
+            continue;
+        }
+
+        header = false;
+        bool first = true;
+
+        UidStatisticsCollection::iterator ut;
+        for(ut = id(i).begin(); ut != id(i).end(); ++ut) {
+            UidStatistics *up = *ut;
+            if ((uid != AID_ROOT) && (uid != up->getUid())) {
+                continue;
+            }
+
+            PidStatisticsCollection::iterator pt = up->begin();
+            if (pt == up->end()) {
+                continue;
+            }
+
+            android::String8 intermediate;
+
+            if (!header) {
+                // header below tuned to match spaces_total and spaces_current
+                spaces = 0;
+                intermediate = string.format("%s: UID/PID Total size/num",
+                                             android_log_id_to_name(i));
+                string.appendFormat("\n\n%-31sNow          "
+                                         "UID/PID[?]  Total              Now",
+                                    intermediate.string());
+                intermediate.clear();
+                header = true;
+            }
+
+            bool oneline = ++pt == up->end();
+            --pt;
+
+            if (!oneline) {
+                first = true;
+            } else if (!first && (spaces > 0)) {
+                string.appendFormat("%*s", spaces, "");
+            }
+            spaces = 0;
+
+            uid_t u = up->getUid();
+            PidStatistics *pp = *pt;
+            pid_t p = pp->getPid();
+
+            intermediate = string.format(oneline
+                                             ? ((p == PidStatistics::gone)
+                                                 ? "%d/?"
+                                                 : "%d/%d%c")
+                                             : "%d",
+                                         u, p, pp->pidGone() ? '?' : '\0');
+            string.appendFormat(first ? "\n%-12s" : "%-12s",
+                                intermediate.string());
+            intermediate.clear();
+
+            size_t elsTotal = up->elementsTotal();
+            oldLength = string.length();
+            string.appendFormat("%zu/%zu", up->sizesTotal(), elsTotal);
+            spaces += spaces_total + oldLength - string.length();
+
+            size_t els = up->elements();
+            if (els == elsTotal) {
+                if (spaces < 0) {
+                    spaces = 0;
+                }
+                string.appendFormat("%*s=", spaces, "");
+                spaces = -1;
+            } else if (els) {
+                oldLength = string.length();
+                if (spaces < 0) {
+                    spaces = 0;
+                }
+                string.appendFormat("%*s%zu/%zu", spaces, "", up->sizes(), els);
+                spaces -= string.length() - oldLength;
+            }
+            spaces += spaces_current;
+
+            first = !first;
+
+            if (oneline) {
+                continue;
+            }
+
+            size_t gone_szs = 0;
+            size_t gone_els = 0;
+
+            for(; pt != up->end(); ++pt) {
+                pp = *pt;
+                p = pp->getPid();
+
+                // If a PID no longer has any current logs, and is not
+                // active anymore, skip & report totals for gone.
+                elsTotal = pp->elementsTotal();
+                size_t szsTotal = pp->sizesTotal();
+                if (p == pp->gone) {
+                    gone_szs += szsTotal;
+                    gone_els += elsTotal;
+                    continue;
+                }
+                els = pp->elements();
+                bool gone = pp->pidGone();
+                if (gone && (els == 0)) {
+                    // ToDo: garbage collection: move this statistical bucket
+                    //       from its current UID/PID to UID/? (races and
+                    //       wrap around are our achilles heel). Below is
+                    //       merely lipservice to catch PIDs that were still
+                    //       around when the stats were pruned to zero.
+                    gone_szs += szsTotal;
+                    gone_els += elsTotal;
+                    continue;
+                }
+
+                if (!first && (spaces > 0)) {
+                    string.appendFormat("%*s", spaces, "");
+                }
+                spaces = 0;
+
+                intermediate = string.format(gone ? "%d/%d?" : "%d/%d", u, p);
+                string.appendFormat(first ? "\n%-12s" : "%-12s",
+                                    intermediate.string());
+                intermediate.clear();
+
+                oldLength = string.length();
+                string.appendFormat("%zu/%zu", szsTotal, elsTotal);
+                spaces += spaces_total + oldLength - string.length();
+
+                if (els == elsTotal) {
+                    if (spaces < 0) {
+                        spaces = 0;
+                    }
+                    string.appendFormat("%*s=", spaces, "");
+                    spaces = -1;
+                } else if (els) {
+                    oldLength = string.length();
+                    if (spaces < 0) {
+                        spaces = 0;
+                    }
+                    string.appendFormat("%*s%zu/%zu", spaces, "",
+                                        pp->sizes(), els);
+                    spaces -= string.length() - oldLength;
+                }
+                spaces += spaces_current;
+
+                first = !first;
+            }
+
+            if (gone_els) {
+                if (!first && (spaces > 0)) {
+                    string.appendFormat("%*s", spaces, "");
+                }
+
+                intermediate = string.format("%d/?", u);
+                string.appendFormat(first ? "\n%-12s" : "%-12s",
+                                    intermediate.string());
+                intermediate.clear();
+
+                spaces = spaces_total + spaces_current;
+
+                oldLength = string.length();
+                string.appendFormat("%zu/%zu", gone_szs, gone_els);
+                spaces -= string.length() - oldLength;
+
+                first = !first;
+            }
+        }
+    }
+
+    *buf = strdup(string.string());
+}
+
+uid_t LogStatistics::pidToUid(pid_t pid) {
+    log_id_for_each(i) {
+        LidStatistics &l = id(i);
+        UidStatisticsCollection::iterator iu;
+        for (iu = l.begin(); iu != l.end(); ++iu) {
+            UidStatistics &u = *(*iu);
+            PidStatisticsCollection::iterator ip;
+            for (ip = u.begin(); ip != u.end(); ++ip) {
+                if ((*ip)->getPid() == pid) {
+                    return u.getUid();
+                }
+            }
+        }
+    }
+    return getuid(); // associate this with the logger
+}
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
new file mode 100644
index 0000000..3733137
--- /dev/null
+++ b/logd/LogStatistics.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2014 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 _LOGD_LOG_STATISTICS_H__
+#define _LOGD_LOG_STATISTICS_H__
+
+#include <sys/types.h>
+
+#include <log/log.h>
+#include <log/log_read.h>
+#include <utils/List.h>
+
+#define log_id_for_each(i) \
+    for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t) (i + 1))
+
+class PidStatistics {
+    const pid_t pid;
+
+    // Total
+    size_t mSizesTotal;
+    size_t mElementsTotal;
+    // Current
+    size_t mSizes;
+    size_t mElements;
+
+    char *name;
+    bool mGone;
+
+public:
+    static const pid_t gone = (pid_t) -1;
+
+    PidStatistics(pid_t pid, char *name = NULL);
+    PidStatistics(const PidStatistics &copy);
+    ~PidStatistics();
+
+    pid_t getPid() const { return pid; }
+    bool pidGone();
+    char *getName() const { return name; }
+    void setName(char *name);
+
+    void add(unsigned short size);
+    bool subtract(unsigned short size); // returns true if stats and PID gone
+    void addTotal(size_t size, size_t element);
+
+    size_t sizes() const { return mSizes; }
+    size_t elements() const { return mElements; }
+
+    size_t sizesTotal() const { return mSizesTotal; }
+    size_t elementsTotal() const { return mElementsTotal; }
+
+    // helper
+    static char *pidToName(pid_t pid);
+};
+
+typedef android::List<PidStatistics *> PidStatisticsCollection;
+
+class UidStatistics {
+    const uid_t uid;
+
+    PidStatisticsCollection Pids;
+
+    size_t mSizes;
+    size_t mElements;
+
+public:
+    UidStatistics(uid_t uid);
+    ~UidStatistics();
+
+    PidStatisticsCollection::iterator begin() { return Pids.begin(); }
+    PidStatisticsCollection::iterator end() { return Pids.end(); }
+
+    uid_t getUid() { return uid; }
+
+    void add(unsigned short size, pid_t pid);
+    void subtract(unsigned short size, pid_t pid);
+    void sort();
+
+    static const pid_t pid_all = (pid_t) -1;
+
+    // fast track current value
+    size_t sizes() const { return mSizes; };
+    size_t elements() const { return mElements; };
+
+    // statistical track
+    size_t sizes(pid_t pid);
+    size_t elements(pid_t pid);
+
+    size_t sizesTotal(pid_t pid = pid_all);
+    size_t elementsTotal(pid_t pid = pid_all);
+
+    // helper
+    static char *pidToName(pid_t pid) { return PidStatistics::pidToName(pid); }
+};
+
+typedef android::List<UidStatistics *> UidStatisticsCollection;
+
+class LidStatistics {
+    UidStatisticsCollection Uids;
+
+public:
+    LidStatistics();
+    ~LidStatistics();
+
+    UidStatisticsCollection::iterator begin() { return Uids.begin(); }
+    UidStatisticsCollection::iterator end() { return Uids.end(); }
+
+    void add(unsigned short size, uid_t uid, pid_t pid);
+    void subtract(unsigned short size, uid_t uid, pid_t pid);
+    void sort();
+
+    static const pid_t pid_all = (pid_t) -1;
+    static const uid_t uid_all = (uid_t) -1;
+
+    size_t sizes(uid_t uid = uid_all, pid_t pid = pid_all);
+    size_t elements(uid_t uid = uid_all, pid_t pid = pid_all);
+
+    size_t sizesTotal(uid_t uid = uid_all, pid_t pid = pid_all);
+    size_t elementsTotal(uid_t uid = uid_all, pid_t pid = pid_all);
+};
+
+// Log Statistics
+class LogStatistics {
+    LidStatistics LogIds[LOG_ID_MAX];
+
+    size_t mSizes[LOG_ID_MAX];
+    size_t mElements[LOG_ID_MAX];
+
+    bool dgram_qlen_statistics;
+
+    static const unsigned short mBuckets[14];
+    log_time mMinimum[sizeof(mBuckets) / sizeof(mBuckets[0])];
+
+public:
+    const log_time start;
+
+    LogStatistics();
+
+    LidStatistics &id(log_id_t log_id) { return LogIds[log_id]; }
+
+    void enableDgramQlenStatistics() { dgram_qlen_statistics = true; }
+    static unsigned short dgram_qlen(unsigned short bucket);
+    unsigned long long minimum(unsigned short bucket);
+    void recordDiff(log_time diff, unsigned short bucket);
+
+    void add(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid);
+    void subtract(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid);
+    void sort();
+
+    // fast track current value by id only
+    size_t sizes(log_id_t id) const { return mSizes[id]; }
+    size_t elements(log_id_t id) const { return mElements[id]; }
+
+    // statistical track
+    static const log_id_t log_id_all = (log_id_t) -1;
+    static const uid_t uid_all = (uid_t) -1;
+    static const pid_t pid_all = (pid_t) -1;
+
+    size_t sizes(log_id_t id, uid_t uid, pid_t pid = pid_all);
+    size_t elements(log_id_t id, uid_t uid, pid_t pid = pid_all);
+    size_t sizes() { return sizes(log_id_all, uid_all); }
+    size_t elements() { return elements(log_id_all, uid_all); }
+
+    size_t sizesTotal(log_id_t id = log_id_all,
+                      uid_t uid = uid_all,
+                      pid_t pid = pid_all);
+    size_t elementsTotal(log_id_t id = log_id_all,
+                         uid_t uid = uid_all,
+                         pid_t pid = pid_all);
+
+    // *strp = malloc, balance with free
+    void format(char **strp, uid_t uid, unsigned int logMask, log_time oldest);
+
+    // helper
+    static char *pidToName(pid_t pid) { return PidStatistics::pidToName(pid); }
+    uid_t pidToUid(pid_t pid);
+};
+
+#endif // _LOGD_LOG_STATISTICS_H__
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
new file mode 100644
index 0000000..e7e3ec2
--- /dev/null
+++ b/logd/LogTimes.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2014 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 <sys/prctl.h>
+
+#include "FlushCommand.h"
+#include "LogBuffer.h"
+#include "LogTimes.h"
+#include "LogReader.h"
+
+pthread_mutex_t LogTimeEntry::timesLock = PTHREAD_MUTEX_INITIALIZER;
+
+const struct timespec LogTimeEntry::EPOCH = { 0, 1 };
+
+LogTimeEntry::LogTimeEntry(LogReader &reader, SocketClient *client,
+                           bool nonBlock, unsigned long tail,
+                           unsigned int logMask, pid_t pid,
+                           log_time start)
+        : mRefCount(1)
+        , mRelease(false)
+        , mError(false)
+        , threadRunning(false)
+        , threadTriggered(true)
+        , mReader(reader)
+        , mLogMask(logMask)
+        , mPid(pid)
+        , skipAhead(0)
+        , mCount(0)
+        , mTail(tail)
+        , mIndex(0)
+        , mClient(client)
+        , mStart(start)
+        , mNonBlock(nonBlock)
+        , mEnd(CLOCK_MONOTONIC)
+{ }
+
+void LogTimeEntry::startReader_Locked(void) {
+    pthread_attr_t attr;
+
+    threadRunning = true;
+
+    if (!pthread_attr_init(&attr)) {
+        if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
+            if (!pthread_create(&mThread, &attr,
+                                LogTimeEntry::threadStart, this)) {
+                pthread_attr_destroy(&attr);
+                return;
+            }
+        }
+        pthread_attr_destroy(&attr);
+    }
+    threadRunning = false;
+    if (mClient) {
+        mClient->decRef();
+    }
+    decRef_Locked();
+}
+
+void LogTimeEntry::threadStop(void *obj) {
+    LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
+
+    lock();
+
+    me->threadRunning = false;
+    if (me->mNonBlock) {
+        me->error_Locked();
+    }
+
+    SocketClient *client = me->mClient;
+
+    if (me->isError_Locked()) {
+        LogReader &reader = me->mReader;
+        LastLogTimes &times = reader.logbuf().mTimes;
+
+        LastLogTimes::iterator it = times.begin();
+        while(it != times.end()) {
+            if (*it == me) {
+                times.erase(it);
+                me->release_Locked();
+                break;
+            }
+            it++;
+        }
+
+        me->mClient = NULL;
+        reader.release(client);
+    }
+
+    if (client) {
+        client->decRef();
+    }
+
+    me->decRef_Locked();
+
+    unlock();
+}
+
+void *LogTimeEntry::threadStart(void *obj) {
+    prctl(PR_SET_NAME, "logd.reader.per");
+
+    LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
+
+    pthread_cleanup_push(threadStop, obj);
+
+    SocketClient *client = me->mClient;
+    if (!client) {
+        me->error();
+        pthread_exit(NULL);
+    }
+
+    LogBuffer &logbuf = me->mReader.logbuf();
+
+    bool privileged = FlushCommand::hasReadLogs(client);
+
+    lock();
+
+    me->threadTriggered = true;
+
+    while(me->threadTriggered && !me->isError_Locked()) {
+
+        me->threadTriggered = false;
+
+        log_time start = me->mStart;
+
+        unlock();
+
+        if (me->mTail) {
+            logbuf.flushTo(client, start, privileged, FilterFirstPass, me);
+        }
+        start = logbuf.flushTo(client, start, privileged, FilterSecondPass, me);
+
+        if (start == LogBufferElement::FLUSH_ERROR) {
+            me->error();
+        }
+
+        if (me->mNonBlock) {
+            lock();
+            break;
+        }
+
+        sched_yield();
+
+        lock();
+    }
+
+    unlock();
+
+    pthread_exit(NULL);
+
+    pthread_cleanup_pop(true);
+
+    return NULL;
+}
+
+// A first pass to count the number of elements
+bool LogTimeEntry::FilterFirstPass(const LogBufferElement *element, void *obj) {
+    LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
+
+    LogTimeEntry::lock();
+
+    if (me->mCount == 0) {
+        me->mStart = element->getMonotonicTime();
+    }
+
+    if ((!me->mPid || (me->mPid == element->getPid()))
+            && (me->mLogMask & (1 << element->getLogId()))) {
+        ++me->mCount;
+    }
+
+    LogTimeEntry::unlock();
+
+    return false;
+}
+
+// A second pass to send the selected elements
+bool LogTimeEntry::FilterSecondPass(const LogBufferElement *element, void *obj) {
+    LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
+
+    LogTimeEntry::lock();
+
+    if (me->skipAhead) {
+        me->skipAhead--;
+        goto skip;
+    }
+
+    me->mStart = element->getMonotonicTime();
+
+    // Truncate to close race between first and second pass
+    if (me->mNonBlock && me->mTail && (me->mIndex >= me->mCount)) {
+        goto skip;
+    }
+
+    if ((me->mLogMask & (1 << element->getLogId())) == 0) {
+        goto skip;
+    }
+
+    if (me->mPid && (me->mPid != element->getPid())) {
+        goto skip;
+    }
+
+    if (me->isError_Locked()) {
+        goto skip;
+    }
+
+    if (!me->mTail) {
+        goto ok;
+    }
+
+    ++me->mIndex;
+
+    if ((me->mCount > me->mTail) && (me->mIndex <= (me->mCount - me->mTail))) {
+        goto skip;
+    }
+
+    if (!me->mNonBlock) {
+        me->mTail = 0;
+    }
+
+ok:
+    if (!me->skipAhead) {
+        LogTimeEntry::unlock();
+        return true;
+    }
+    // FALLTHRU
+
+skip:
+    LogTimeEntry::unlock();
+    return false;
+}
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
new file mode 100644
index 0000000..beaf646
--- /dev/null
+++ b/logd/LogTimes.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2012-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 _LOGD_LOG_TIMES_H__
+#define _LOGD_LOG_TIMES_H__
+
+#include <pthread.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sysutils/SocketClient.h>
+#include <utils/List.h>
+
+class LogReader;
+
+class LogTimeEntry {
+    static pthread_mutex_t timesLock;
+    unsigned int mRefCount;
+    bool mRelease;
+    bool mError;
+    bool threadRunning;
+    bool threadTriggered;
+    pthread_t mThread;
+    LogReader &mReader;
+    static void *threadStart(void *me);
+    static void threadStop(void *me);
+    const unsigned int mLogMask;
+    const pid_t mPid;
+    unsigned int skipAhead;
+    unsigned long mCount;
+    unsigned long mTail;
+    unsigned long mIndex;
+
+public:
+    LogTimeEntry(LogReader &reader, SocketClient *client, bool nonBlock,
+                 unsigned long tail, unsigned int logMask, pid_t pid,
+                 log_time start);
+
+    SocketClient *mClient;
+    static const struct timespec EPOCH;
+    log_time mStart;
+    const bool mNonBlock;
+    const log_time mEnd; // only relevant if mNonBlock
+
+    // Protect List manipulations
+    static void lock(void) { pthread_mutex_lock(&timesLock); }
+    static void unlock(void) { pthread_mutex_unlock(&timesLock); }
+
+    void startReader_Locked(void);
+
+    bool runningReader_Locked(void) const {
+        return threadRunning || mRelease || mError || mNonBlock;
+    }
+    void triggerReader_Locked(void) { threadTriggered = true; }
+    void triggerSkip_Locked(unsigned int skip) { skipAhead = skip; }
+
+    // Called after LogTimeEntry removed from list, lock implicitly held
+    void release_Locked(void) {
+        mRelease = true;
+        if (mRefCount || threadRunning) {
+            return;
+        }
+        // No one else is holding a reference to this
+        delete this;
+    }
+
+    // Called to mark socket in jeopardy
+    void error_Locked(void) { mError = true; }
+    void error(void) { lock(); mError = true; unlock(); }
+
+    bool isError_Locked(void) const { return mRelease || mError; }
+
+    // Mark Used
+    //  Locking implied, grabbed when protection around loop iteration
+    void incRef_Locked(void) { ++mRefCount; }
+
+    bool owned_Locked(void) const { return mRefCount != 0; }
+
+    void decRef_Locked(void) {
+        if ((mRefCount && --mRefCount) || !mRelease || threadRunning) {
+            return;
+        }
+        // No one else is holding a reference to this
+        delete this;
+    }
+
+    // flushTo filter callbacks
+    static bool FilterFirstPass(const LogBufferElement *element, void *me);
+    static bool FilterSecondPass(const LogBufferElement *element, void *me);
+};
+
+typedef android::List<LogTimeEntry *> LastLogTimes;
+
+#endif
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
new file mode 100644
index 0000000..e87b604
--- /dev/null
+++ b/logd/LogWhiteBlackList.cpp
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2014 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 <ctype.h>
+
+#include <utils/String8.h>
+
+#include "LogWhiteBlackList.h"
+
+// White and Black list
+
+Prune::Prune(uid_t uid, pid_t pid)
+        : mUid(uid)
+        , mPid(pid)
+{ }
+
+int Prune::cmp(uid_t uid, pid_t pid) const {
+    if ((mUid == uid_all) || (mUid == uid)) {
+        if (mPid == pid_all) {
+            return 0;
+        }
+        return pid - mPid;
+    }
+    return uid - mUid;
+}
+
+void Prune::format(char **strp) {
+    if (mUid != uid_all) {
+        asprintf(strp, (mPid != pid_all) ? "%u/%u" : "%u", mUid, mPid);
+    } else {
+        // NB: mPid == pid_all can not happen if mUid == uid_all
+        asprintf(strp, (mPid != pid_all) ? "/%u" : "/", mPid);
+    }
+}
+
+PruneList::PruneList()
+        : mWorstUidEnabled(false) {
+    mNaughty.clear();
+    mNice.clear();
+}
+
+PruneList::~PruneList() {
+    PruneCollection::iterator it;
+    for (it = mNice.begin(); it != mNice.end();) {
+        delete (*it);
+        it = mNice.erase(it);
+    }
+    for (it = mNaughty.begin(); it != mNaughty.end();) {
+        delete (*it);
+        it = mNaughty.erase(it);
+    }
+}
+
+int PruneList::init(char *str) {
+    mWorstUidEnabled = false;
+    PruneCollection::iterator it;
+    for (it = mNice.begin(); it != mNice.end();) {
+        delete (*it);
+        it = mNice.erase(it);
+    }
+    for (it = mNaughty.begin(); it != mNaughty.end();) {
+        delete (*it);
+        it = mNaughty.erase(it);
+    }
+
+    if (!str) {
+        return 0;
+    }
+
+    mWorstUidEnabled = false;
+
+    for(; *str; ++str) {
+        if (isspace(*str)) {
+            continue;
+        }
+
+        PruneCollection *list;
+        if ((*str == '~') || (*str == '!')) { // ~ supported, ! undocumented
+            ++str;
+            // special case, translates to worst UID at priority in blacklist
+            if (*str == '!') {
+                mWorstUidEnabled = true;
+                ++str;
+                if (!*str) {
+                    break;
+                }
+                if (!isspace(*str)) {
+                    return 1;
+                }
+                continue;
+            }
+            if (!*str) {
+                return 1;
+            }
+            list = &mNaughty;
+        } else {
+            list = &mNice;
+        }
+
+        uid_t uid = Prune::uid_all;
+        if (isdigit(*str)) {
+            uid = 0;
+            do {
+                uid = uid * 10 + *str++ - '0';
+            } while (isdigit(*str));
+        }
+
+        pid_t pid = Prune::pid_all;
+        if (*str == '/') {
+            ++str;
+            if (isdigit(*str)) {
+                pid = 0;
+                do {
+                    pid = pid * 10 + *str++ - '0';
+                } while (isdigit(*str));
+            }
+        }
+
+        if ((uid == Prune::uid_all) && (pid == Prune::pid_all)) {
+            return 1;
+        }
+
+        if (*str && !isspace(*str)) {
+            return 1;
+        }
+
+        // insert sequentially into list
+        PruneCollection::iterator it = list->begin();
+        while (it != list->end()) {
+            Prune *p = *it;
+            int m = uid - p->mUid;
+            if (m == 0) {
+                if (p->mPid == p->pid_all) {
+                    break;
+                }
+                if ((pid == p->pid_all) && (p->mPid != p->pid_all)) {
+                    it = list->erase(it);
+                    continue;
+                }
+                m = pid - p->mPid;
+            }
+            if (m <= 0) {
+                if (m < 0) {
+                    list->insert(it, new Prune(uid,pid));
+                }
+                break;
+            }
+            ++it;
+        }
+        if (it == list->end()) {
+            list->push_back(new Prune(uid,pid));
+        }
+        if (!*str) {
+            break;
+        }
+    }
+
+    return 0;
+}
+
+void PruneList::format(char **strp) {
+    if (*strp) {
+        free(*strp);
+        *strp = NULL;
+    }
+
+    static const char nice_format[] = " %s";
+    const char *fmt = nice_format + 1;
+
+    android::String8 string;
+
+    if (mWorstUidEnabled) {
+        string.setTo("~!");
+        fmt = nice_format;
+    }
+
+    PruneCollection::iterator it;
+
+    for (it = mNice.begin(); it != mNice.end(); ++it) {
+        char *a = NULL;
+        (*it)->format(&a);
+
+        string.appendFormat(fmt, a);
+        fmt = nice_format;
+
+        free(a);
+    }
+
+    static const char naughty_format[] = " ~%s";
+    fmt = naughty_format + (*fmt != ' ');
+    for (it = mNaughty.begin(); it != mNaughty.end(); ++it) {
+        char *a = NULL;
+        (*it)->format(&a);
+
+        string.appendFormat(fmt, a);
+        fmt = naughty_format;
+
+        free(a);
+    }
+
+    *strp = strdup(string.string());
+}
+
+// ToDo: Lists are in sorted order, Prune->cmp() returns + or -
+// If there is scaling issues, resort to a better algorithm than linear
+// based on these assumptions.
+
+bool PruneList::naughty(LogBufferElement *element) {
+    PruneCollection::iterator it;
+    for (it = mNaughty.begin(); it != mNaughty.end(); ++it) {
+        if (!(*it)->cmp(element)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool PruneList::nice(LogBufferElement *element) {
+    PruneCollection::iterator it;
+    for (it = mNice.begin(); it != mNice.end(); ++it) {
+        if (!(*it)->cmp(element)) {
+            return true;
+        }
+    }
+    return false;
+}
diff --git a/logd/LogWhiteBlackList.h b/logd/LogWhiteBlackList.h
new file mode 100644
index 0000000..769d651
--- /dev/null
+++ b/logd/LogWhiteBlackList.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2014 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 _LOGD_LOG_WHITE_BLACK_LIST_H__
+#define _LOGD_LOG_WHITE_BLACK_LIST_H__
+
+#include <sys/types.h>
+
+#include <utils/List.h>
+
+#include <LogBufferElement.h>
+
+// White and Blacklist
+
+class Prune {
+    friend class PruneList;
+
+    const uid_t mUid;
+    const pid_t mPid;
+    int cmp(uid_t uid, pid_t pid) const;
+
+public:
+    static const uid_t uid_all = (uid_t) -1;
+    static const pid_t pid_all = (pid_t) -1;
+
+    Prune(uid_t uid, pid_t pid);
+
+    uid_t getUid() const { return mUid; }
+    pid_t getPid() const { return mPid; }
+
+    int cmp(LogBufferElement *e) const { return cmp(e->getUid(), e->getPid()); }
+
+    // *strp is malloc'd, use free to release
+    void format(char **strp);
+};
+
+typedef android::List<Prune *> PruneCollection;
+
+class PruneList {
+    PruneCollection mNaughty;
+    PruneCollection mNice;
+    bool mWorstUidEnabled;
+
+public:
+    PruneList();
+    ~PruneList();
+
+    int init(char *str);
+
+    bool naughty(LogBufferElement *element);
+    bool nice(LogBufferElement *element);
+    bool worstUidEnabled() const { return mWorstUidEnabled; }
+
+    // *strp is malloc'd, use free to release
+    void format(char **strp);
+};
+
+#endif // _LOGD_LOG_WHITE_BLACK_LIST_H__
diff --git a/logd/README.auditd b/logd/README.auditd
new file mode 100644
index 0000000..3f614a3
--- /dev/null
+++ b/logd/README.auditd
@@ -0,0 +1,17 @@
+Auditd Daemon
+
+The audit daemon is a simplified version of its desktop
+counterpart designed to gather the audit logs from the
+audit kernel subsystem. The audit subsystem of the kernel
+includes Linux Security Modules (LSM) messages as well.
+
+To enable the audit subsystem, you must add this to your
+kernel config:
+CONFIG_AUDIT=y
+
+To enable a LSM, you must consult that LSM's documentation, the
+example below is for SELinux:
+CONFIG_SECURITY_SELINUX=y
+
+This does not include possible dependencies that may need to be
+satisfied for that particular LSM.
diff --git a/logd/README.property b/logd/README.property
new file mode 100644
index 0000000..f4b3c3c
--- /dev/null
+++ b/logd/README.property
@@ -0,0 +1,25 @@
+The properties that logd responds to are:
+
+name                       type default  description
+logd.auditd                 bool  true   Enable selinux audit daemon
+logd.auditd.dmesg           bool  true   selinux audit messages duplicated and
+                                         sent on to dmesg log
+logd.statistics.dgram_qlen  bool  false  Record dgram_qlen statistics. This
+                                         represents a performance impact and
+                                         is used to determine the platform's
+                                         minimum domain socket network FIFO
+                                         size (see source for details) based
+                                         on typical load (logcat -S to view)
+persist.logd.size          number 256K   default size of the buffer for all
+                                         log ids at initial startup, at runtime
+                                         use: logcat -b all -G <value>
+persist.logd.size.main     number 256K   Size of the buffer for the main log
+persist.logd.size.system   number 256K   Size of the buffer for the system log
+persist.logd.size.radio    number 256K   Size of the buffer for the radio log
+persist.logd.size.event    number 256K   Size of the buffer for the event log
+persist.logd.size.crash    number 256K   Size of the buffer for the crash log
+
+NB:
+- number support multipliers (K or M) for convenience. Range is limited
+  to between 64K and 256M for log buffer sizes. Individual logs override the
+  global default.
diff --git a/logd/event.logtags b/logd/event.logtags
new file mode 100644
index 0000000..a63f034
--- /dev/null
+++ b/logd/event.logtags
@@ -0,0 +1,36 @@
+# The entries in this file map a sparse set of log tag numbers to tag names.
+# This is installed on the device, in /system/etc, and parsed by logcat.
+#
+# Tag numbers are decimal integers, from 0 to 2^31.  (Let's leave the
+# negative values alone for now.)
+#
+# Tag names are one or more ASCII letters and numbers or underscores, i.e.
+# "[A-Z][a-z][0-9]_".  Do not include spaces or punctuation (the former
+# impacts log readability, the latter makes regex searches more annoying).
+#
+# Tag numbers and names are separated by whitespace.  Blank lines and lines
+# starting with '#' are ignored.
+#
+# Optionally, after the tag names can be put a description for the value(s)
+# of the tag. Description are in the format
+#    (<name>|data type[|data unit])
+# Multiple values are separated by commas.
+#
+# The data type is a number from the following values:
+# 1: int
+# 2: long
+# 3: string
+# 4: list
+#
+# The data unit is a number taken from the following list:
+# 1: Number of objects
+# 2: Number of bytes
+# 3: Number of milliseconds
+# 4: Number of allocations
+# 5: Id
+# 6: Percent
+# Default value for data of type int/long is 2 (bytes).
+#
+# TODO: generate ".java" and ".h" files with integer constants from this file.
+
+1003  auditd (avc|3)
diff --git a/logd/libaudit.c b/logd/libaudit.c
new file mode 100644
index 0000000..ca88d1b
--- /dev/null
+++ b/logd/libaudit.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2012, Samsung Telecommunications of America
+ * Copyright (C) 2014 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.
+ *
+ * Written by William Roberts <w.roberts@sta.samsung.com>
+ *
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LOG_TAG "libaudit"
+#include <log/log.h>
+
+#include "libaudit.h"
+
+/**
+ * Waits for an ack from the kernel
+ * @param fd
+ *  The netlink socket fd
+ * @param seq
+ *  The current sequence number were acking on
+ * @return
+ *  This function returns 0 on success, else -errno.
+ */
+static int get_ack(int fd, int16_t seq)
+{
+    int rc;
+    struct audit_message rep;
+
+    /* Sanity check, this is an internal interface this shouldn't happen */
+    if (fd < 0) {
+        return -EINVAL;
+    }
+
+    rc = audit_get_reply(fd, &rep, GET_REPLY_BLOCKING, MSG_PEEK);
+    if (rc < 0) {
+        return rc;
+    }
+
+    if (rep.nlh.nlmsg_type == NLMSG_ERROR) {
+        audit_get_reply(fd, &rep, GET_REPLY_BLOCKING, 0);
+        rc = ((struct nlmsgerr *)rep.data)->error;
+        if (rc) {
+            return -rc;
+        }
+    }
+
+    if ((int16_t)rep.nlh.nlmsg_seq != seq) {
+        SLOGW("Expected sequence number between user space and kernel space is out of skew, "
+          "expected %u got %u", seq, rep.nlh.nlmsg_seq);
+    }
+
+    return 0;
+}
+
+/**
+ *
+ * @param fd
+ *  The netlink socket fd
+ * @param type
+ *  The type of netlink message
+ * @param data
+ *  The data to send
+ * @param size
+ *  The length of the data in bytes
+ * @return
+ *  This function returns a positive sequence number on success, else -errno.
+ */
+static int audit_send(int fd, int type, const void *data, size_t size)
+{
+    int rc;
+    static int16_t sequence = 0;
+    struct audit_message req;
+    struct sockaddr_nl addr;
+
+    memset(&req, 0, sizeof(req));
+    memset(&addr, 0, sizeof(addr));
+
+    /* We always send netlink messaged */
+    addr.nl_family = AF_NETLINK;
+
+    /* Set up the netlink headers */
+    req.nlh.nlmsg_type = type;
+    req.nlh.nlmsg_len = NLMSG_SPACE(size);
+    req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+
+    /*
+     * Check for a valid fd, even though sendto would catch this, its easier
+     * to always blindly increment the sequence number
+     */
+    if (fd < 0) {
+        return -EBADF;
+    }
+
+    /* Ensure the message is not too big */
+    if (NLMSG_SPACE(size) > MAX_AUDIT_MESSAGE_LENGTH) {
+        SLOGE("netlink message is too large");
+        return -EINVAL;
+    }
+
+    /* Only memcpy in the data if it was specified */
+    if (size && data) {
+        memcpy(NLMSG_DATA(&req.nlh), data, size);
+    }
+
+    /*
+     * Only increment the sequence number on a guarantee
+     * you will send it to the kernel.
+     *
+     * Also, the sequence is defined as a u32 in the kernel
+     * struct. Using an int here might not work on 32/64 bit splits. A
+     * signed 64 bit value can overflow a u32..but a u32
+     * might not fit in the response, so we need to use s32.
+     * Which is still kind of hackish since int could be 16 bits
+     * in size. The only safe type to use here is a signed 16
+     * bit value.
+     */
+    req.nlh.nlmsg_seq = ++sequence;
+
+    /* While failing and its due to interrupts */
+
+    rc = TEMP_FAILURE_RETRY(sendto(fd, &req, req.nlh.nlmsg_len, 0,
+                                   (struct sockaddr*) &addr, sizeof(addr)));
+
+    /* Not all the bytes were sent */
+    if (rc < 0) {
+        rc = -errno;
+        SLOGE("Error sending data over the netlink socket: %s", strerror(-errno));
+        goto out;
+    } else if ((uint32_t) rc != req.nlh.nlmsg_len) {
+        rc = -EPROTO;
+        goto out;
+    }
+
+    /* We sent all the bytes, get the ack */
+    rc = get_ack(fd, sequence);
+
+    /* If the ack failed, return the error, else return the sequence number */
+    rc = (rc == 0) ? (int) sequence : rc;
+
+out:
+    /* Don't let sequence roll to negative */
+    if (sequence < 0) {
+        SLOGW("Auditd to Kernel sequence number has rolled over");
+        sequence = 0;
+    }
+
+    return rc;
+}
+
+int audit_set_pid(int fd, uint32_t pid, rep_wait_t wmode)
+{
+    int rc;
+    struct audit_message rep;
+    struct audit_status status;
+
+    memset(&status, 0, sizeof(status));
+
+    /*
+     * In order to set the auditd PID we send an audit message over the netlink
+     * socket with the pid field of the status struct set to our current pid,
+     * and the the mask set to AUDIT_STATUS_PID
+     */
+    status.pid = pid;
+    status.mask = AUDIT_STATUS_PID;
+
+    /* Let the kernel know this pid will be registering for audit events */
+    rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
+    if (rc < 0) {
+        SLOGE("Could net set pid for audit events, error: %s", strerror(-rc));
+        return rc;
+    }
+
+    /*
+     * In a request where we need to wait for a response, wait for the message
+     * and discard it. This message confirms and sync's us with the kernel.
+     * This daemon is now registered as the audit logger. Only wait if the
+     * wmode is != WAIT_NO
+     */
+    if (wmode != WAIT_NO) {
+        /* TODO
+         * If the daemon dies and restarts the message didn't come back,
+         * so I went to non-blocking and it seemed to fix the bug.
+         * Need to investigate further.
+         */
+        audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0);
+    }
+
+    return 0;
+}
+
+int audit_open()
+{
+    return socket(PF_NETLINK, SOCK_RAW, NETLINK_AUDIT);
+}
+
+int audit_get_reply(int fd, struct audit_message *rep, reply_t block, int peek)
+{
+    ssize_t len;
+    int flags;
+    int rc = 0;
+
+    struct sockaddr_nl nladdr;
+    socklen_t nladdrlen = sizeof(nladdr);
+
+    if (fd < 0) {
+        return -EBADF;
+    }
+
+    /* Set up the flags for recv from */
+    flags = (block == GET_REPLY_NONBLOCKING) ? MSG_DONTWAIT : 0;
+    flags |= peek;
+
+    /*
+     * Get the data from the netlink socket but on error we need to be carefull,
+     * the interface shows that EINTR can never be returned, other errors,
+     * however, can be returned.
+     */
+    len = TEMP_FAILURE_RETRY(recvfrom(fd, rep, sizeof(*rep), flags,
+                                      (struct sockaddr*) &nladdr, &nladdrlen));
+
+    /*
+     * EAGAIN should be re-tried until success or another error manifests.
+     */
+    if (len < 0) {
+        rc = -errno;
+        if (block == GET_REPLY_NONBLOCKING && rc == -EAGAIN) {
+            /* If request is non blocking and errno is EAGAIN, just return 0 */
+            return 0;
+        }
+        SLOGE("Error receiving from netlink socket, error: %s", strerror(-rc));
+        return rc;
+    }
+
+    if (nladdrlen != sizeof(nladdr)) {
+        SLOGE("Protocol fault, error: %s", strerror(EPROTO));
+        return -EPROTO;
+    }
+
+    /* Make sure the netlink message was not spoof'd */
+    if (nladdr.nl_pid) {
+        SLOGE("Invalid netlink pid received, expected 0 got: %d", nladdr.nl_pid);
+        return -EINVAL;
+    }
+
+    /* Check if the reply from the kernel was ok */
+    if (!NLMSG_OK(&rep->nlh, (size_t)len)) {
+        rc = (len == sizeof(*rep)) ? -EFBIG : -EBADE;
+        SLOGE("Bad kernel response %s", strerror(-rc));
+    }
+
+    return rc;
+}
+
+void audit_close(int fd)
+{
+    int rc = close(fd);
+    if (rc < 0) {
+        SLOGE("Attempting to close invalid fd %d, error: %s", fd, strerror(errno));
+    }
+    return;
+}
diff --git a/logd/libaudit.h b/logd/libaudit.h
new file mode 100644
index 0000000..cb114f9
--- /dev/null
+++ b/logd/libaudit.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2012, Samsung Telecommunications of America
+ * Copyright (C) 2014 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.
+ *
+ * Written by William Roberts <w.roberts@sta.samsung.com>
+ */
+
+#ifndef _LIBAUDIT_H_
+#define _LIBAUDIT_H_
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <linux/netlink.h>
+#include <linux/audit.h>
+
+__BEGIN_DECLS
+
+#define MAX_AUDIT_MESSAGE_LENGTH    8970
+
+typedef enum {
+    GET_REPLY_BLOCKING=0,
+    GET_REPLY_NONBLOCKING
+} reply_t;
+
+typedef enum {
+    WAIT_NO,
+    WAIT_YES
+} rep_wait_t;
+
+/* type == AUDIT_SIGNAL_INFO */
+struct audit_sig_info {
+    uid_t uid;
+    pid_t pid;
+    char ctx[0];
+};
+
+struct audit_message {
+    struct nlmsghdr nlh;
+    char   data[MAX_AUDIT_MESSAGE_LENGTH];
+};
+
+/**
+ * Opens a connection to the Audit netlink socket
+ * @return
+ *  A valid fd on success or < 0 on error with errno set.
+ *  Returns the same errors as man 2 socket.
+ */
+extern int  audit_open(void);
+
+/**
+ * Closes the fd returned from audit_open()
+ * @param fd
+ *  The fd to close
+ */
+extern void audit_close(int fd);
+
+/**
+ *
+ * @param fd
+ *  The fd returned by a call to audit_open()
+ * @param rep
+ *  The response struct to store the response in.
+ * @param block
+ *  Whether or not to block on IO
+ * @param peek
+ *  Whether or not we are to remove the message from
+ *  the queue when we do a read on the netlink socket.
+ * @return
+ *  This function returns 0 on success, else -errno.
+ */
+extern int  audit_get_reply(int fd, struct audit_message *rep, reply_t block,
+               int peek);
+
+/**
+ * Sets a pid to recieve audit netlink events from the kernel
+ * @param fd
+ *  The fd returned by a call to audit_open()
+ * @param pid
+ *  The pid whom to set as the reciever of audit messages
+ * @param wmode
+ *  Whether or not to block on the underlying socket io calls.
+ * @return
+ *  This function returns 0 on success, -errno on error.
+ */
+extern int  audit_set_pid(int fd, uint32_t pid, rep_wait_t wmode);
+
+__END_DECLS
+
+#endif
diff --git a/logd/main.cpp b/logd/main.cpp
new file mode 100644
index 0000000..ece5a3a
--- /dev/null
+++ b/logd/main.cpp
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2012-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.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/capability.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/prctl.h>
+
+#include <cutils/properties.h>
+
+#include "private/android_filesystem_config.h"
+#include "CommandListener.h"
+#include "LogBuffer.h"
+#include "LogListener.h"
+#include "LogAudit.h"
+
+//
+//  The service is designed to be run by init, it does not respond well
+// to starting up manually. When starting up manually the sockets will
+// fail to open typically for one of the following reasons:
+//     EADDRINUSE if logger is running.
+//     EACCESS if started without precautions (below)
+//
+// Here is a cookbook procedure for starting up logd manually assuming
+// init is out of the way, pedantically all permissions and selinux
+// security is put back in place:
+//
+//    setenforce 0
+//    rm /dev/socket/logd*
+//    chmod 777 /dev/socket
+//        # here is where you would attach the debugger or valgrind for example
+//    runcon u:r:logd:s0 /system/bin/logd </dev/null >/dev/null 2>&1 &
+//    sleep 1
+//    chmod 755 /dev/socket
+//    chown logd.logd /dev/socket/logd*
+//    restorecon /dev/socket/logd*
+//    setenforce 1
+//
+// If minimalism prevails, typical for debugging and security is not a concern:
+//
+//    setenforce 0
+//    chmod 777 /dev/socket
+//    logd
+//
+
+static int drop_privs() {
+    struct sched_param param;
+    memset(&param, 0, sizeof(param));
+
+    if (sched_setscheduler((pid_t) 0, SCHED_BATCH, &param) < 0) {
+        return -1;
+    }
+
+    if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
+        return -1;
+    }
+
+    if (setgid(AID_LOGD) != 0) {
+        return -1;
+    }
+
+    if (setuid(AID_LOGD) != 0) {
+        return -1;
+    }
+
+    struct __user_cap_header_struct capheader;
+    struct __user_cap_data_struct capdata[2];
+    memset(&capheader, 0, sizeof(capheader));
+    memset(&capdata, 0, sizeof(capdata));
+    capheader.version = _LINUX_CAPABILITY_VERSION_3;
+    capheader.pid = 0;
+
+    capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG);
+    capdata[CAP_TO_INDEX(CAP_AUDIT_CONTROL)].permitted |= CAP_TO_MASK(CAP_AUDIT_CONTROL);
+
+    capdata[0].effective = capdata[0].permitted;
+    capdata[1].effective = capdata[1].permitted;
+    capdata[0].inheritable = 0;
+    capdata[1].inheritable = 0;
+
+    if (capset(&capheader, &capdata[0]) < 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+// Property helper
+static bool property_get_bool(const char *key, bool def) {
+    char property[PROPERTY_VALUE_MAX];
+    property_get(key, property, "");
+
+    if (!strcasecmp(property, "true")) {
+        return true;
+    }
+    if (!strcasecmp(property, "false")) {
+        return false;
+    }
+
+    return def;
+}
+
+// Foreground waits for exit of the three main persistent threads that
+// are started here.  The three threads are created to manage UNIX
+// domain client sockets for writing, reading and controlling the user
+// space logger.  Additional transitory per-client threads are created
+// for each reader once they register.
+int main() {
+    bool auditd = property_get_bool("logd.auditd", true);
+
+    int fdDmesg = -1;
+    if (auditd && property_get_bool("logd.auditd.dmesg", true)) {
+        fdDmesg = open("/dev/kmsg", O_WRONLY);
+    }
+
+    if (drop_privs() != 0) {
+        return -1;
+    }
+
+    // Serves the purpose of managing the last logs times read on a
+    // socket connection, and as a reader lock on a range of log
+    // entries.
+
+    LastLogTimes *times = new LastLogTimes();
+
+    // LogBuffer is the object which is responsible for holding all
+    // log entries.
+
+    LogBuffer *logBuf = new LogBuffer(times);
+
+    if (property_get_bool("logd.statistics.dgram_qlen", false)) {
+        logBuf->enableDgramQlenStatistics();
+    }
+
+    // LogReader listens on /dev/socket/logdr. When a client
+    // connects, log entries in the LogBuffer are written to the client.
+
+    LogReader *reader = new LogReader(logBuf);
+    if (reader->startListener()) {
+        exit(1);
+    }
+
+    // LogListener listens on /dev/socket/logdw for client
+    // initiated log messages. New log entries are added to LogBuffer
+    // and LogReader is notified to send updates to connected clients.
+
+    LogListener *swl = new LogListener(logBuf, reader);
+    // Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value
+    if (swl->startListener(300)) {
+        exit(1);
+    }
+
+    // Command listener listens on /dev/socket/logd for incoming logd
+    // administrative commands.
+
+    CommandListener *cl = new CommandListener(logBuf, reader, swl);
+    if (cl->startListener()) {
+        exit(1);
+    }
+
+    // LogAudit listens on NETLINK_AUDIT socket for selinux
+    // initiated log messages. New log entries are added to LogBuffer
+    // and LogReader is notified to send updates to connected clients.
+
+    if (auditd) {
+        // failure is an option ... messages are in dmesg (required by standard)
+        LogAudit *al = new LogAudit(logBuf, reader, fdDmesg);
+        if (al->startListener()) {
+            delete al;
+            close(fdDmesg);
+        }
+    }
+
+    pause();
+    exit(0);
+}
+
diff --git a/logd/tests/Android.mk b/logd/tests/Android.mk
new file mode 100644
index 0000000..f851288
--- /dev/null
+++ b/logd/tests/Android.mk
@@ -0,0 +1,53 @@
+#
+# Copyright (C) 2014 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+# -----------------------------------------------------------------------------
+# Benchmarks. (see ../../liblog/tests)
+# -----------------------------------------------------------------------------
+
+test_module_prefix := logd-
+test_tags := tests
+
+# -----------------------------------------------------------------------------
+# Unit tests.
+# -----------------------------------------------------------------------------
+
+test_c_flags := \
+    -fstack-protector-all \
+    -g \
+    -Wall -Wextra \
+    -Werror \
+    -fno-builtin \
+
+ifneq ($(TARGET_USES_LOGD),false)
+test_c_flags += -DTARGET_USES_LOGD=1
+endif
+
+test_src_files := \
+    logd_test.cpp
+
+# Build tests for the logger. Run with:
+#   adb shell /data/nativetest/logd-unit-tests/logd-unit-tests
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(test_module_prefix)unit-tests
+LOCAL_MODULE_TAGS := $(test_tags)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_CFLAGS += $(test_c_flags)
+LOCAL_SHARED_LIBRARIES := libcutils
+LOCAL_SRC_FILES := $(test_src_files)
+include $(BUILD_NATIVE_TEST)
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
new file mode 100644
index 0000000..957fdb5
--- /dev/null
+++ b/logd/tests/logd_test.cpp
@@ -0,0 +1,703 @@
+/*
+ * Copyright (C) 2014 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 <fcntl.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <gtest/gtest.h>
+
+#include "cutils/sockets.h"
+#include "log/log.h"
+#include "log/logger.h"
+
+#define __unused __attribute__((__unused__))
+
+/*
+ * returns statistics
+ */
+static void my_android_logger_get_statistics(char *buf, size_t len)
+{
+    snprintf(buf, len, "getStatistics 0 1 2 3 4");
+    int sock = socket_local_client("logd",
+                                   ANDROID_SOCKET_NAMESPACE_RESERVED,
+                                   SOCK_STREAM);
+    if (sock >= 0) {
+        if (write(sock, buf, strlen(buf) + 1) > 0) {
+            ssize_t ret;
+            while ((ret = read(sock, buf, len)) > 0) {
+                if ((size_t)ret == len) {
+                    break;
+                }
+                len -= ret;
+                buf += ret;
+
+                struct pollfd p = {
+                    .fd = sock,
+                    .events = POLLIN,
+                    .revents = 0
+                };
+
+                ret = poll(&p, 1, 20);
+                if ((ret <= 0) || !(p.revents & POLLIN)) {
+                    break;
+                }
+            }
+        }
+        close(sock);
+    }
+}
+
+static void alloc_statistics(char **buffer, size_t *length)
+{
+    size_t len = 8192;
+    char *buf;
+
+    for(int retry = 32; (retry >= 0); delete [] buf, --retry) {
+        buf = new char [len];
+        my_android_logger_get_statistics(buf, len);
+
+        buf[len-1] = '\0';
+        size_t ret = atol(buf) + 1;
+        if (ret < 4) {
+            delete [] buf;
+            buf = NULL;
+            break;
+        }
+        bool check = ret <= len;
+        len = ret;
+        if (check) {
+            break;
+        }
+        len += len / 8; // allow for some slop
+    }
+    *buffer = buf;
+    *length = len;
+}
+
+static char *find_benchmark_spam(char *cp)
+{
+    // liblog_benchmarks has been run designed to SPAM.  The signature of
+    // a noisiest UID statistics is one of the following:
+    //
+    // main: UID/PID Total size/num   Now          UID/PID[?]  Total
+    // 0           7500306/304207     71608/3183   0/4225?     7454388/303656
+    //    <wrap>                                                     93432/1012
+    // -or-
+    // 0/gone      7454388/303656     93432/1012
+    //
+    // basically if we see a *large* number of 0/????? entries
+    unsigned long value;
+    do {
+        char *benchmark = strstr(cp, " 0/");
+        char *benchmark_newline = strstr(cp, "\n0/");
+        if (!benchmark) {
+            benchmark = benchmark_newline;
+        }
+        if (benchmark_newline && (benchmark > benchmark_newline)) {
+            benchmark = benchmark_newline;
+        }
+        cp = benchmark;
+        if (!cp) {
+            break;
+        }
+        cp += 3;
+        while (isdigit(*cp) || (*cp == 'g') || (*cp == 'o') || (*cp == 'n')) {
+            ++cp;
+        }
+        value = 0;
+        // ###? or gone
+        if ((*cp == '?') || (*cp == 'e')) {
+            while (*++cp == ' ');
+            while (isdigit(*cp)) {
+                value = value * 10ULL + *cp - '0';
+                ++cp;
+            }
+            if (*cp != '/') {
+                value = 0;
+                continue;
+            }
+            while (isdigit(*++cp));
+            while (*cp == ' ') ++cp;
+            if (!isdigit(*cp)) {
+                value = 0;
+            }
+        }
+    } while ((value < 900000ULL) && *cp);
+    return cp;
+}
+
+TEST(logd, statistics) {
+    size_t len;
+    char *buf;
+
+    alloc_statistics(&buf, &len);
+
+#ifdef TARGET_USES_LOGD
+    ASSERT_TRUE(NULL != buf);
+#else
+    if (!buf) {
+        return;
+    }
+#endif
+
+    // remove trailing FF
+    char *cp = buf + len - 1;
+    *cp = '\0';
+    bool truncated = *--cp != '\f';
+    if (!truncated) {
+        *cp = '\0';
+    }
+
+    // squash out the byte count
+    cp = buf;
+    if (!truncated) {
+        while (isdigit(*cp) || (*cp == '\n')) {
+            ++cp;
+        }
+    }
+
+    fprintf(stderr, "%s", cp);
+
+    EXPECT_LT((size_t)64, strlen(cp));
+
+    EXPECT_EQ(0, truncated);
+
+#ifdef TARGET_USES_LOGD
+    char *main_logs = strstr(cp, "\nmain:");
+    EXPECT_TRUE(NULL != main_logs);
+
+    char *radio_logs = strstr(cp, "\nradio:");
+    EXPECT_TRUE(NULL != radio_logs);
+
+    char *system_logs = strstr(cp, "\nsystem:");
+    EXPECT_TRUE(NULL != system_logs);
+
+    char *events_logs = strstr(cp, "\nevents:");
+    EXPECT_TRUE(NULL != events_logs);
+#endif
+
+    // Parse timing stats
+
+    cp = strstr(cp, "Minimum time between log events per dgram_qlen:");
+
+    if (cp) {
+        while (*cp && (*cp != '\n')) {
+            ++cp;
+        }
+        if (*cp == '\n') {
+            ++cp;
+        }
+
+        char *list_of_spans = cp;
+        EXPECT_NE('\0', *list_of_spans);
+
+        unsigned short number_of_buckets = 0;
+        unsigned short *dgram_qlen = NULL;
+        unsigned short bucket = 0;
+        while (*cp && (*cp != '\n')) {
+            bucket = 0;
+            while (isdigit(*cp)) {
+                bucket = bucket * 10 + *cp - '0';
+                ++cp;
+            }
+            while (*cp == ' ') {
+                ++cp;
+            }
+            if (!bucket) {
+                break;
+            }
+            unsigned short *new_dgram_qlen = new unsigned short[number_of_buckets + 1];
+            EXPECT_TRUE(new_dgram_qlen != NULL);
+            if (dgram_qlen) {
+                memcpy(new_dgram_qlen, dgram_qlen, sizeof(*dgram_qlen) * number_of_buckets);
+                delete [] dgram_qlen;
+            }
+
+            dgram_qlen = new_dgram_qlen;
+            dgram_qlen[number_of_buckets++] = bucket;
+        }
+
+        char *end_of_spans = cp;
+        EXPECT_NE('\0', *end_of_spans);
+
+        EXPECT_LT(5, number_of_buckets);
+
+        unsigned long long *times = new unsigned long long [number_of_buckets];
+        ASSERT_TRUE(times != NULL);
+
+        memset(times, 0, sizeof(*times) * number_of_buckets);
+
+        while (*cp == '\n') {
+            ++cp;
+        }
+
+        unsigned short number_of_values = 0;
+        unsigned long long value;
+        while (*cp && (*cp != '\n')) {
+            EXPECT_GE(number_of_buckets, number_of_values);
+
+            value = 0;
+            while (isdigit(*cp)) {
+                value = value * 10ULL + *cp - '0';
+                ++cp;
+            }
+
+            switch(*cp) {
+            case ' ':
+            case '\n':
+                value *= 1000ULL;
+                /* FALLTHRU */
+            case 'm':
+                value *= 1000ULL;
+                /* FALLTHRU */
+            case 'u':
+                value *= 1000ULL;
+                /* FALLTHRU */
+            case 'n':
+            default:
+                break;
+            }
+            while (*++cp == ' ');
+
+            if (!value) {
+                break;
+            }
+
+            times[number_of_values] = value;
+            ++number_of_values;
+        }
+
+#ifdef TARGET_USES_LOGD
+        EXPECT_EQ(number_of_values, number_of_buckets);
+#endif
+
+        FILE *fp;
+        ASSERT_TRUE(NULL != (fp = fopen("/proc/sys/net/unix/max_dgram_qlen", "r")));
+
+        unsigned max_dgram_qlen = 0;
+        fscanf(fp, "%u", &max_dgram_qlen);
+
+        fclose(fp);
+
+        // Find launch point
+        unsigned short launch = 0;
+        unsigned long long total = 0;
+        do {
+            total += times[launch];
+        } while (((++launch < number_of_buckets)
+                && ((total / launch) >= (times[launch] / 8ULL)))
+            || (launch == 1)); // too soon
+
+        bool failure = number_of_buckets <= launch;
+        if (!failure) {
+            unsigned short l = launch;
+            if (l >= number_of_buckets) {
+                l = number_of_buckets - 1;
+            }
+            failure = max_dgram_qlen < dgram_qlen[l];
+        }
+
+        // We can get failure if at any time liblog_benchmarks has been run
+        // because designed to overload /proc/sys/net/unix/max_dgram_qlen even
+        // at excessive values like 20000. It does so to measure the raw processing
+        // performance of logd.
+        if (failure) {
+            cp = find_benchmark_spam(cp);
+        }
+
+        if (cp) {
+            // Fake a failure, but without the failure code
+            if (number_of_buckets <= launch) {
+                printf ("Expected: number_of_buckets > launch, actual: %u vs %u\n",
+                        number_of_buckets, launch);
+            }
+            if (launch >= number_of_buckets) {
+                launch = number_of_buckets - 1;
+            }
+            if (max_dgram_qlen < dgram_qlen[launch]) {
+                printf ("Expected: max_dgram_qlen >= dgram_qlen[%d],"
+                            " actual: %u vs %u\n",
+                        launch, max_dgram_qlen, dgram_qlen[launch]);
+            }
+        } else
+#ifndef TARGET_USES_LOGD
+        if (total)
+#endif
+        {
+            EXPECT_GT(number_of_buckets, launch);
+            if (launch >= number_of_buckets) {
+                launch = number_of_buckets - 1;
+            }
+            EXPECT_GE(max_dgram_qlen, dgram_qlen[launch]);
+        }
+
+        delete [] dgram_qlen;
+        delete [] times;
+    }
+    delete [] buf;
+}
+
+static void caught_signal(int signum __unused) { }
+
+static void dump_log_msg(const char *prefix,
+                         log_msg *msg, unsigned int version, int lid) {
+    switch(msg->entry.hdr_size) {
+    case 0:
+        version = 1;
+        break;
+
+    case sizeof(msg->entry_v2):
+        if (version == 0) {
+            version = 2;
+        }
+        break;
+    }
+
+    fprintf(stderr, "%s: v%u[%u] ", prefix, version, msg->len());
+    if (version != 1) {
+        fprintf(stderr, "hdr_size=%u ", msg->entry.hdr_size);
+    }
+    fprintf(stderr, "pid=%u tid=%u %u.%09u ",
+            msg->entry.pid, msg->entry.tid, msg->entry.sec, msg->entry.nsec);
+    switch(version) {
+    case 1:
+         break;
+    case 2:
+        fprintf(stderr, "euid=%u ", msg->entry_v2.euid);
+        break;
+    case 3:
+    default:
+        lid = msg->entry.lid;
+        break;
+    }
+
+    switch(lid) {
+    case 0:
+        fprintf(stderr, "lid=main ");
+        break;
+    case 1:
+        fprintf(stderr, "lid=radio ");
+        break;
+    case 2:
+        fprintf(stderr, "lid=events ");
+        break;
+    case 3:
+        fprintf(stderr, "lid=system ");
+        break;
+    default:
+        if (lid >= 0) {
+            fprintf(stderr, "lid=%d ", lid);
+        }
+    }
+
+    unsigned int len = msg->entry.len;
+    fprintf(stderr, "msg[%u]={", len);
+    unsigned char *cp = reinterpret_cast<unsigned char *>(msg->msg());
+    while(len) {
+        unsigned char *p = cp;
+        while (*p && (((' ' <= *p) && (*p < 0x7F)) || (*p == '\n'))) {
+            ++p;
+        }
+        if (((p - cp) > 3) && !*p && ((unsigned int)(p - cp) < len)) {
+            fprintf(stderr, "\"");
+            while (*cp) {
+                fprintf(stderr, (*cp != '\n') ? "%c" : "\\n", *cp);
+                ++cp;
+                --len;
+            }
+            fprintf(stderr, "\"");
+        } else {
+            fprintf(stderr, "%02x", *cp);
+        }
+        ++cp;
+        if (--len) {
+            fprintf(stderr, ", ");
+        }
+    }
+    fprintf(stderr, "}\n");
+}
+
+TEST(logd, both) {
+    log_msg msg;
+
+    // check if we can read any logs from logd
+    bool user_logger_available = false;
+    bool user_logger_content = false;
+
+    int fd = socket_local_client("logdr",
+                                 ANDROID_SOCKET_NAMESPACE_RESERVED,
+                                 SOCK_SEQPACKET);
+    if (fd >= 0) {
+        struct sigaction ignore, old_sigaction;
+        memset(&ignore, 0, sizeof(ignore));
+        ignore.sa_handler = caught_signal;
+        sigemptyset(&ignore.sa_mask);
+        sigaction(SIGALRM, &ignore, &old_sigaction);
+        unsigned int old_alarm = alarm(10);
+
+        static const char ask[] = "dumpAndClose lids=0,1,2,3";
+        user_logger_available = write(fd, ask, sizeof(ask)) == sizeof(ask);
+
+        user_logger_content = recv(fd, msg.buf, sizeof(msg), 0) > 0;
+
+        if (user_logger_content) {
+            dump_log_msg("user", &msg, 3, -1);
+        }
+
+        alarm(old_alarm);
+        sigaction(SIGALRM, &old_sigaction, NULL);
+
+        close(fd);
+    }
+
+    // check if we can read any logs from kernel logger
+    bool kernel_logger_available = false;
+    bool kernel_logger_content = false;
+
+    static const char *loggers[] = {
+        "/dev/log/main",   "/dev/log_main",
+        "/dev/log/radio",  "/dev/log_radio",
+        "/dev/log/events", "/dev/log_events",
+        "/dev/log/system", "/dev/log_system",
+    };
+
+    for (unsigned int i = 0; i < (sizeof(loggers) / sizeof(loggers[0])); ++i) {
+        fd = open(loggers[i], O_RDONLY);
+        if (fd < 0) {
+            continue;
+        }
+        kernel_logger_available = true;
+        fcntl(fd, F_SETFL, O_RDONLY | O_NONBLOCK);
+        int result = TEMP_FAILURE_RETRY(read(fd, msg.buf, sizeof(msg)));
+        if (result > 0) {
+            kernel_logger_content = true;
+            dump_log_msg("kernel", &msg, 0, i / 2);
+        }
+        close(fd);
+    }
+
+    static const char yes[] = "\xE2\x9C\x93";
+    static const char no[] = "\xE2\x9c\x98";
+    fprintf(stderr,
+            "LOGGER  Available  Content\n"
+            "user    %-13s%s\n"
+            "kernel  %-13s%s\n"
+            " status %-11s%s\n",
+            (user_logger_available)   ? yes : no,
+            (user_logger_content)     ? yes : no,
+            (kernel_logger_available) ? yes : no,
+            (kernel_logger_content)   ? yes : no,
+            (user_logger_available && kernel_logger_available) ? "WARNING" : "ok",
+            (user_logger_content && kernel_logger_content) ? "ERROR" : "ok");
+
+    if (user_logger_available && kernel_logger_available) {
+        printf("WARNING: kernel & user logger; both consuming resources!!!\n");
+    }
+
+    EXPECT_EQ(0, user_logger_content && kernel_logger_content);
+    EXPECT_EQ(0, !user_logger_content && !kernel_logger_content);
+}
+
+// BAD ROBOT
+//   Benchmark threshold are generally considered bad form unless there is
+//   is some human love applied to the continued maintenance and whether the
+//   thresholds are tuned on a per-target basis. Here we check if the values
+//   are more than double what is expected. Doubling will not prevent failure
+//   on busy or low-end systems that could have a tendency to stretch values.
+//
+//   The primary goal of this test is to simulate a spammy app (benchmark
+//   being the worst) and check to make sure the logger can deal with it
+//   appropriately by checking all the statistics are in an expected range.
+//
+TEST(logd, benchmark) {
+    size_t len;
+    char *buf;
+
+    alloc_statistics(&buf, &len);
+    bool benchmark_already_run = buf && find_benchmark_spam(buf);
+    delete [] buf;
+
+    if (benchmark_already_run) {
+        fprintf(stderr, "WARNING: spam already present and too much history\n"
+                        "         false OK for prune by worst UID check\n");
+    }
+
+    FILE *fp;
+
+    // Introduce some extreme spam for the worst UID filter
+    ASSERT_TRUE(NULL != (fp = popen(
+        "/data/nativetest/liblog-benchmarks/liblog-benchmarks",
+        "r")));
+
+    char buffer[5120];
+
+    static const char *benchmarks[] = {
+        "BM_log_maximum_retry ",
+        "BM_log_maximum ",
+        "BM_clock_overhead ",
+        "BM_log_overhead ",
+        "BM_log_latency ",
+        "BM_log_delay "
+    };
+    static const unsigned int log_maximum_retry = 0;
+    static const unsigned int log_maximum = 1;
+    static const unsigned int clock_overhead = 2;
+    static const unsigned int log_overhead = 3;
+    static const unsigned int log_latency = 4;
+    static const unsigned int log_delay = 5;
+
+    unsigned long ns[sizeof(benchmarks) / sizeof(benchmarks[0])];
+
+    memset(ns, 0, sizeof(ns));
+
+    while (fgets(buffer, sizeof(buffer), fp)) {
+        for (unsigned i = 0; i < sizeof(ns) / sizeof(ns[0]); ++i) {
+            char *cp = strstr(buffer, benchmarks[i]);
+            if (!cp) {
+                continue;
+            }
+            sscanf(cp, "%*s %lu %lu", &ns[i], &ns[i]);
+            fprintf(stderr, "%-22s%8lu\n", benchmarks[i], ns[i]);
+        }
+    }
+    int ret = pclose(fp);
+
+    if (!WIFEXITED(ret) || (WEXITSTATUS(ret) == 127)) {
+        fprintf(stderr,
+                "WARNING: "
+                "/data/nativetest/liblog-benchmarks/liblog-benchmarks missing\n"
+                "         can not perform test\n");
+        return;
+    }
+
+#ifdef TARGET_USES_LOGD
+    EXPECT_GE(100000UL, ns[log_maximum_retry]); // 42777 user
+#else
+    EXPECT_GE(10000UL, ns[log_maximum_retry]); // 5636 kernel
+#endif
+
+#ifdef TARGET_USES_LOGD
+    EXPECT_GE(30000UL, ns[log_maximum]); // 27305 user
+#else
+    EXPECT_GE(10000UL, ns[log_maximum]); // 5637 kernel
+#endif
+
+    EXPECT_GE(4096UL, ns[clock_overhead]); // 4095
+
+#ifdef TARGET_USES_LOGD
+    EXPECT_GE(250000UL, ns[log_overhead]); // 121876 user
+#else
+    EXPECT_GE(100000UL, ns[log_overhead]); // 50945 kernel
+#endif
+
+#ifdef TARGET_USES_LOGD
+    EXPECT_GE(7500UL, ns[log_latency]); // 3718 user space
+#else
+    EXPECT_GE(500000UL, ns[log_latency]); // 254200 kernel
+#endif
+
+#ifdef TARGET_USES_LOGD
+    EXPECT_GE(20000000UL, ns[log_delay]); // 10500289 user
+#else
+    EXPECT_GE(55000UL, ns[log_delay]); // 27341 kernel
+#endif
+
+    for (unsigned i = 0; i < sizeof(ns) / sizeof(ns[0]); ++i) {
+        EXPECT_NE(0UL, ns[i]);
+    }
+
+    alloc_statistics(&buf, &len);
+
+#ifdef TARGET_USES_LOGD
+    bool collected_statistics = !!buf;
+    EXPECT_EQ(true, collected_statistics);
+#else
+    if (!buf) {
+        return;
+    }
+#endif
+
+    ASSERT_TRUE(NULL != buf);
+
+    char *benchmark_statistics_found = find_benchmark_spam(buf);
+    ASSERT_TRUE(benchmark_statistics_found != NULL);
+
+    // Check how effective the SPAM filter is, parse out Now size.
+    //             Total               Now
+    // 0/4225?     7454388/303656      31488/755
+    //                                 ^-- benchmark_statistics_found
+
+    unsigned long nowSpamSize = atol(benchmark_statistics_found);
+
+    delete [] buf;
+
+    ASSERT_NE(0UL, nowSpamSize);
+
+    // Determine if we have the spam filter enabled
+    int sock = socket_local_client("logd",
+                                   ANDROID_SOCKET_NAMESPACE_RESERVED,
+                                   SOCK_STREAM);
+
+    ASSERT_TRUE(sock >= 0);
+
+    static const char getPruneList[] = "getPruneList";
+    if (write(sock, getPruneList, sizeof(getPruneList)) > 0) {
+        char buffer[80];
+        memset(buffer, 0, sizeof(buffer));
+        read(sock, buffer, sizeof(buffer));
+        char *cp = strchr(buffer, '\n');
+        if (!cp || (cp[1] != '~') || (cp[2] != '!')) {
+            close(sock);
+            fprintf(stderr,
+                    "WARNING: "
+                    "Logger has SPAM filtration turned off \"%s\"\n", buffer);
+            return;
+        }
+    } else {
+        int save_errno = errno;
+        close(sock);
+        FAIL() << "Can not send " << getPruneList << " to logger -- " << strerror(save_errno);
+    }
+
+    static const unsigned long expected_absolute_minimum_log_size = 65536UL;
+    unsigned long totalSize = expected_absolute_minimum_log_size;
+    static const char getSize[] = {
+        'g', 'e', 't', 'L', 'o', 'g', 'S', 'i', 'z', 'e', ' ',
+        LOG_ID_MAIN + '0', '\0'
+    };
+    if (write(sock, getSize, sizeof(getSize)) > 0) {
+        char buffer[80];
+        memset(buffer, 0, sizeof(buffer));
+        read(sock, buffer, sizeof(buffer));
+        totalSize = atol(buffer);
+        if (totalSize < expected_absolute_minimum_log_size) {
+            fprintf(stderr,
+                    "WARNING: "
+                    "Logger had unexpected referenced size \"%s\"\n", buffer);
+            totalSize = expected_absolute_minimum_log_size;
+        }
+    }
+    close(sock);
+
+    // logd allows excursions to 110% of total size
+    totalSize = (totalSize * 11 ) / 10;
+
+    // 50% threshold for SPAM filter (<20% typical, lots of engineering margin)
+    ASSERT_GT(totalSize, nowSpamSize * 2);
+}
diff --git a/logwrapper/Android.mk b/logwrapper/Android.mk
index 917bf37..61b4659 100644
--- a/logwrapper/Android.mk
+++ b/logwrapper/Android.mk
@@ -11,6 +11,7 @@
 LOCAL_SHARED_LIBRARIES := libcutils liblog
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Werror
 include $(BUILD_STATIC_LIBRARY)
 
 # ========================================================
@@ -22,6 +23,7 @@
 LOCAL_WHOLE_STATIC_LIBRARIES := liblogwrap
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Werror
 include $(BUILD_SHARED_LIBRARY)
 
 # ========================================================
@@ -31,4 +33,5 @@
 LOCAL_SRC_FILES:= logwrapper.c
 LOCAL_MODULE := logwrapper
 LOCAL_STATIC_LIBRARIES := liblog liblogwrap libcutils
+LOCAL_CFLAGS := -Werror
 include $(BUILD_EXECUTABLE)
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index 4ca1db4..d47c9b5 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -104,8 +104,6 @@
 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) {
@@ -124,7 +122,6 @@
 {
     ssize_t free_len;
     ssize_t needed_space;
-    char *new_buf;
     int cnt;
 
     if (e_buf->buf == NULL) {
@@ -192,7 +189,6 @@
 {
     char *line_start;
     char c;
-    int line_len;
     int i;
 
     line_start = buf;
diff --git a/mkbootimg/Android.mk b/mkbootimg/Android.mk
index 2a97c26..0c9b0c6 100644
--- a/mkbootimg/Android.mk
+++ b/mkbootimg/Android.mk
@@ -4,6 +4,7 @@
 
 LOCAL_SRC_FILES := mkbootimg.c
 LOCAL_STATIC_LIBRARIES := libmincrypt
+LOCAL_CFLAGS := -Werror
 
 LOCAL_MODULE := mkbootimg
 
diff --git a/mkbootimg/mkbootimg.c b/mkbootimg/mkbootimg.c
index d598f03..fc92b4d 100644
--- a/mkbootimg/mkbootimg.c
+++ b/mkbootimg/mkbootimg.c
@@ -77,7 +77,7 @@
 int write_padding(int fd, unsigned pagesize, unsigned itemsize)
 {
     unsigned pagemask = pagesize - 1;
-    unsigned count;
+    ssize_t count;
 
     if((itemsize & pagemask) == 0) {
         return 0;
@@ -108,7 +108,7 @@
     unsigned pagesize = 2048;
     int fd;
     SHA_CTX ctx;
-    uint8_t* sha;
+    const uint8_t* sha;
     unsigned base           = 0x10000000;
     unsigned kernel_offset  = 0x00008000;
     unsigned ramdisk_offset = 0x01000000;
@@ -189,7 +189,7 @@
         return usage();
     }
 
-    strcpy(hdr.name, board);
+    strcpy((char *) hdr.name, board);
 
     memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
 
@@ -255,15 +255,15 @@
     if(write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) goto fail;
     if(write_padding(fd, pagesize, sizeof(hdr))) goto fail;
 
-    if(write(fd, kernel_data, hdr.kernel_size) != hdr.kernel_size) goto fail;
+    if(write(fd, kernel_data, hdr.kernel_size) != (ssize_t) hdr.kernel_size) goto fail;
     if(write_padding(fd, pagesize, hdr.kernel_size)) goto fail;
 
-    if(write(fd, ramdisk_data, hdr.ramdisk_size) != hdr.ramdisk_size) goto fail;
+    if(write(fd, ramdisk_data, hdr.ramdisk_size) != (ssize_t) hdr.ramdisk_size) goto fail;
     if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail;
 
     if(second_data) {
-        if(write(fd, second_data, hdr.second_size) != hdr.second_size) goto fail;
-        if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail;
+        if(write(fd, second_data, hdr.second_size) != (ssize_t) hdr.second_size) goto fail;
+        if(write_padding(fd, pagesize, hdr.second_size)) goto fail;
     }
 
     return 0;
diff --git a/netcfg/Android.mk b/netcfg/Android.mk
index 949f417..fc01a54 100644
--- a/netcfg/Android.mk
+++ b/netcfg/Android.mk
@@ -11,6 +11,7 @@
 #LOCAL_STATIC_LIBRARIES := libcutils libc
 
 LOCAL_SHARED_LIBRARIES := libc libnetutils
+LOCAL_CFLAGS := -Werror
 
 include $(BUILD_EXECUTABLE)
 endif
diff --git a/netcfg/netcfg.c b/netcfg/netcfg.c
index 3738f24..2308f37 100644
--- a/netcfg/netcfg.c
+++ b/netcfg/netcfg.c
@@ -1,5 +1,4 @@
-/* system/bin/netcfg/netcfg.c
-**
+/*
 ** Copyright 2006, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License"); 
@@ -15,18 +14,14 @@
 ** limitations under the License.
 */
 
-#include <stdio.h>
-#include <stdlib.h>
 #include <errno.h>
 #include <dirent.h>
 #include <netinet/ether.h>
 #include <netinet/if_ether.h>
-
-#include <netutils/ifc.h>
 #include <netutils/dhcp.h>
-
-static int verbose = 0;
-
+#include <netutils/ifc.h>
+#include <stdio.h>
+#include <stdlib.h>
 
 void die(const char *reason)
 {
diff --git a/reboot/Android.mk b/reboot/Android.mk
index 4db0c1e..7a24f99 100644
--- a/reboot/Android.mk
+++ b/reboot/Android.mk
@@ -1,12 +1,14 @@
 # Copyright 2013 The Android Open Source Project
 
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:= reboot.c
+LOCAL_SRC_FILES := reboot.c
 
-LOCAL_SHARED_LIBRARIES:= libcutils
+LOCAL_SHARED_LIBRARIES := libcutils
 
-LOCAL_MODULE:= reboot
+LOCAL_MODULE := reboot
+
+LOCAL_CFLAGS := -Werror
 
 include $(BUILD_EXECUTABLE)
diff --git a/reboot/reboot.c b/reboot/reboot.c
index d9a4227..007dfba 100644
--- a/reboot/reboot.c
+++ b/reboot/reboot.c
@@ -35,7 +35,7 @@
 
         c = getopt(argc, argv, "p");
 
-        if (c == EOF) {
+        if (c == -1) {
             break;
         }
 
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 2c16084..aca08bf 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -30,9 +30,17 @@
 
 include $(BUILD_SYSTEM)/base_rules.mk
 
-$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/init.environ.rc.in
+# Regenerate init.environ.rc if PRODUCT_BOOTCLASSPATH has changed.
+bcp_md5 := $(word 1, $(shell echo $(PRODUCT_BOOTCLASSPATH) | $(MD5SUM)))
+bcp_dep := $(intermediates)/$(bcp_md5).bcp.dep
+$(bcp_dep) :
+	$(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.bcp.dep && touch $@
+
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/init.environ.rc.in $(bcp_dep)
 	@echo "Generate: $< -> $@"
 	@mkdir -p $(dir $@)
 	$(hide) sed -e 's?%BOOTCLASSPATH%?$(PRODUCT_BOOTCLASSPATH)?g' $< >$@
 
+bcp_md5 :=
+bcp_dep :=
 #######################################
diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in
index 927c33d..1f964e3 100644
--- a/rootdir/init.environ.rc.in
+++ b/rootdir/init.environ.rc.in
@@ -9,3 +9,4 @@
     export ASEC_MOUNTPOINT /mnt/asec
     export LOOP_MOUNTPOINT /mnt/obb
     export BOOTCLASSPATH %BOOTCLASSPATH%
+    export LD_PRELOAD libsigchain.so
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 90c8187..b59e31f 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -7,6 +7,7 @@
 import /init.environ.rc
 import /init.usb.rc
 import /init.${ro.hardware}.rc
+import /init.${ro.zygote}.rc
 import /init.trace.rc
 
 on early-init
@@ -25,29 +26,28 @@
 
     start ueventd
 
-# create mountpoints
+    # create mountpoints
     mkdir /mnt 0775 root system
 
 on init
+    sysclktz 0
 
-sysclktz 0
+    loglevel 3
 
-loglevel 3
-
-# Backward compatibility
+    # Backward compatibility
     symlink /system/etc /etc
     symlink /sys/kernel/debug /d
 
-# Right now vendor lives on the same filesystem as system,
-# but someday that may change.
+    # Right now vendor lives on the same filesystem as system,
+    # but someday that may change.
     symlink /system/vendor /vendor
 
-# Create cgroup mount point for cpu accounting
+    # Create cgroup mount point for cpu accounting
     mkdir /acct
     mount cgroup none /acct cpuacct
     mkdir /acct/uid
 
-# Create cgroup mount point for memory
+    # Create cgroup mount point for memory
     mount tmpfs none /sys/fs/cgroup mode=0750,uid=0,gid=1000
     mkdir /sys/fs/cgroup/memory 0750 root system
     mount cgroup none /sys/fs/cgroup/memory memory
@@ -101,13 +101,20 @@
     write /proc/sys/kernel/sched_child_runs_first 0
     write /proc/sys/kernel/randomize_va_space 2
     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/net/unix/max_dgram_qlen 300
     write /proc/sys/kernel/sched_rt_runtime_us 950000
     write /proc/sys/kernel/sched_rt_period_us 1000000
 
-# Create cgroup mount points for process groups
+    # reflect fwmark from incoming packets onto generated replies
+    write /proc/sys/net/ipv4/fwmark_reflect 1
+    write /proc/sys/net/ipv6/fwmark_reflect 1
+
+    # set fwmark on accepted sockets
+    write /proc/sys/net/ipv4/tcp_fwmark_accept 1
+
+    # Create cgroup mount points for process groups
     mkdir /dev/cpuctl
     mount cgroup none /dev/cpuctl cpu
     chown system system /dev/cpuctl
@@ -132,25 +139,50 @@
     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.
+    # 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.
+    # 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
 
-# Create location for fs_mgr to store abbreviated output from filesystem
-# checker programs.
+    # Create location for fs_mgr to store abbreviated output from filesystem
+    # checker programs.
     mkdir /dev/fscklogs 0770 root system
 
-# pstore/ramoops previous console log
+    # pstore/ramoops previous console log
     mount pstore pstore /sys/fs/pstore
     chown system log /sys/fs/pstore/console-ramoops
     chmod 0440 /sys/fs/pstore/console-ramoops
 
+# Healthd can trigger a full boot from charger mode by signaling this
+# property when the power button is held.
+on property:sys.boot_from_charger_mode=1
+    class_stop charger
+    trigger late-init
+
+# Load properties from /system/ + /factory after fs mount.
+on load_all_props_action
+    load_all_props
+
+# Mount filesystems and start core system services.
+on late-init
+    trigger early-fs
+    trigger fs
+    trigger post-fs
+    trigger post-fs-data
+
+    # Load properties from /system/ + /factory after fs mount. Place
+    # this in another action so that the load will be scheduled after the prior
+    # issued fs triggers have completed.
+    trigger load_all_props_action
+
+    trigger early-boot
+    trigger boot
+
 on post-fs
     # once everything is setup, no need to modify /
     mount rootfs rootfs / ro remount
@@ -161,13 +193,11 @@
     chown system cache /cache
     chmod 0770 /cache
     # We restorecon /cache in case the cache partition has been reset.
-    restorecon /cache
+    restorecon_recursive /cache
 
     # This may have been created by the recovery system with odd permissions
     chown system cache /cache/recovery
     chmod 0770 /cache/recovery
-    # This may have been created by the recovery system with the wrong context.
-    restorecon /cache/recovery
 
     #change permissions on vmallocinfo so we can grab it from bugreports
     chown root log /proc/vmallocinfo
@@ -184,6 +214,9 @@
     chown system log /proc/last_kmsg
     chmod 0440 /proc/last_kmsg
 
+    # make the selinux kernel policy world-readable
+    chmod 0444 /sys/fs/selinux/policy
+
     # create the lost+found directories, so as to enforce our permissions
     mkdir /cache/lost+found 0770 root root
 
@@ -220,26 +253,22 @@
     mkdir /data/misc/bluetooth 0770 system system
     mkdir /data/misc/keystore 0700 keystore keystore
     mkdir /data/misc/keychain 0771 system system
+    mkdir /data/misc/net 0750 root shell
     mkdir /data/misc/radio 0770 system radio
     mkdir /data/misc/sms 0770 system radio
     mkdir /data/misc/zoneinfo 0775 system system
-    restorecon_recursive /data/misc/zoneinfo
     mkdir /data/misc/vpn 0770 system vpn
+    mkdir /data/misc/shared_relro 0771 shared_relro shared_relro
     mkdir /data/misc/systemkeys 0700 system system
     mkdir /data/misc/wifi 0770 wifi wifi
     mkdir /data/misc/wifi/sockets 0770 wifi wifi
-    restorecon_recursive /data/misc/wifi/sockets
     mkdir /data/misc/wifi/wpa_supplicant 0770 wifi wifi
     mkdir /data/misc/dhcp 0770 dhcp dhcp
+    mkdir /data/misc/user 0771 root root
     # give system access to wpa_supplicant.conf for backup and restore
     chmod 0660 /data/misc/wifi/wpa_supplicant.conf
     mkdir /data/local 0751 root root
     mkdir /data/misc/media 0700 media media
-    restorecon_recursive /data/misc/media
-
-    # Set security context of any pre-existing /data/misc/adb/adb_keys file.
-    restorecon /data/misc/adb
-    restorecon /data/misc/adb/adb_keys
 
     # For security reasons, /data/local/tmp should always be empty.
     # Do not place files or directories in /data/local/tmp
@@ -250,11 +279,10 @@
     mkdir /data/app-lib 0771 system system
     mkdir /data/app 0771 system system
     mkdir /data/property 0700 root root
-    mkdir /data/ssh 0750 root shell
-    mkdir /data/ssh/empty 0700 root root
 
     # create dalvik-cache, so as to enforce our permissions
     mkdir /data/dalvik-cache 0771 system system
+    mkdir /data/dalvik-cache/profiles 0711 system system
 
     # create resource-cache and double-check the perms
     mkdir /data/resource-cache 0771 system system
@@ -271,7 +299,6 @@
     # create directory for MediaDrm plug-ins - give drm the read/write access to
     # the following directory.
     mkdir /data/mediadrm 0770 mediadrm mediadrm
-    restorecon_recursive /data/mediadrm
 
     # symlink to bugreport storage location
     symlink /data/data/com.android.shell/files/bugreports /data/bugreports
@@ -282,6 +309,9 @@
     # Reload policy from /data/security if present.
     setprop selinux.reload_policy 1
 
+    # Set SELinux security contexts on upgrade or policy update.
+    restorecon_recursive /data
+
     # 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.
@@ -289,17 +319,17 @@
     #setprop vold.post_fs_data_done 1
 
 on boot
-# basic network init
+    # basic network init
     ifup lo
     hostname localhost
     domainname localdomain
 
-# set RLIMIT_NICE to allow priorities from 19 to -20
+    # set RLIMIT_NICE to allow priorities from 19 to -20
     setrlimit 13 40 40
 
-# Memory management.  Basic kernel parameters, and allow the high
-# level system server to be able to adjust the kernel OOM driver
-# parameters to match how it is managing things.
+    # Memory management.  Basic kernel parameters, and allow the high
+    # level system server to be able to adjust the kernel OOM driver
+    # parameters to match how it is managing things.
     write /proc/sys/vm/overcommit_memory 1
     write /proc/sys/vm/min_free_order_shift 4
     chown root system /sys/module/lowmemorykiller/parameters/adj
@@ -375,22 +405,22 @@
     chown system system /sys/kernel/ipv4/tcp_rmem_max
     chown root radio /proc/cmdline
 
-# Define TCP buffer sizes for various networks
-#   ReadMin, ReadInitial, ReadMax, WriteMin, WriteInitial, WriteMax,
+    # Define TCP buffer sizes for various networks
+    #   ReadMin, ReadInitial, ReadMax, WriteMin, WriteInitial, WriteMax,
     setprop net.tcp.buffersize.default  4096,87380,110208,4096,16384,110208
     setprop net.tcp.buffersize.wifi     524288,1048576,2097152,262144,524288,1048576
     setprop net.tcp.buffersize.ethernet 524288,1048576,3145728,524288,1048576,2097152
     setprop net.tcp.buffersize.lte      524288,1048576,2097152,262144,524288,1048576
-    setprop net.tcp.buffersize.umts     4094,87380,110208,4096,16384,110208
-    setprop net.tcp.buffersize.hspa     4094,87380,262144,4096,16384,262144
-    setprop net.tcp.buffersize.hsupa    4094,87380,262144,4096,16384,262144
-    setprop net.tcp.buffersize.hsdpa    4094,87380,262144,4096,16384,262144
-    setprop net.tcp.buffersize.hspap    4094,87380,1220608,4096,16384,1220608
-    setprop net.tcp.buffersize.edge     4093,26280,35040,4096,16384,35040
-    setprop net.tcp.buffersize.gprs     4092,8760,11680,4096,8760,11680
+    setprop net.tcp.buffersize.umts     58254,349525,1048576,58254,349525,1048576
+    setprop net.tcp.buffersize.hspa     40778,244668,734003,16777,100663,301990
+    setprop net.tcp.buffersize.hsupa    40778,244668,734003,16777,100663,301990
+    setprop net.tcp.buffersize.hsdpa    61167,367002,1101005,8738,52429,262114
+    setprop net.tcp.buffersize.hspap    122334,734003,2202010,32040,192239,576717
+    setprop net.tcp.buffersize.edge     4093,26280,70800,4096,16384,70800
+    setprop net.tcp.buffersize.gprs     4092,8760,48000,4096,8760,48000
     setprop net.tcp.buffersize.evdo     4094,87380,262144,4096,16384,262144
 
-# Define default initial receive window size in segments.
+    # Define default initial receive window size in segments.
     setprop net.tcp.default_init_rwnd 60
 
     class_start core
@@ -399,6 +429,9 @@
 on nonencrypted
     class_start late_start
 
+on property:sys.init_log_level=*
+    loglevel ${sys.init_log_level}
+
 on charger
     class_start charger
 
@@ -430,6 +463,7 @@
 # So proxy writes through init.
 on property:sys.sysctl.extra_free_kbytes=*
     write /proc/sys/vm/extra_free_kbytes ${sys.sysctl.extra_free_kbytes}
+
 # "tcp_default_init_rwnd" Is too long!
 on property:sys.sysctl.tcp_def_init_rwnd=*
     write /proc/sys/net/ipv4/tcp_default_init_rwnd ${sys.sysctl.tcp_def_init_rwnd}
@@ -442,6 +476,13 @@
     critical
     seclabel u:r:ueventd:s0
 
+service logd /system/bin/logd
+    class core
+    socket logd stream 0666 logd logd
+    socket logdr seqpacket 0666 logd logd
+    socket logdw dgram 0222 logd logd
+    seclabel u:r:logd:s0
+
 service healthd /sbin/healthd
     class core
     critical
@@ -457,7 +498,7 @@
     console
     disabled
     user shell
-    group log
+    group shell log
     seclabel u:r:shell:s0
 
 on property:ro.debuggable=1
@@ -500,10 +541,14 @@
     socket netd stream 0660 root system
     socket dnsproxyd stream 0660 root inet
     socket mdns stream 0660 root system
+    socket fwmarkd stream 0660 root inet
 
 service debuggerd /system/bin/debuggerd
     class main
 
+service debuggerd64 /system/bin/debuggerd64
+    class main
+
 service ril-daemon /system/bin/rild
     class main
     socket rild stream 660 root radio
@@ -517,14 +562,6 @@
     group graphics drmrpc
     onrestart restart zygote
 
-service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
-    class main
-    socket zygote stream 660 root system
-    onrestart write /sys/android_power/request_state wake
-    onrestart write /sys/power/state on
-    onrestart restart media
-    onrestart restart netd
-
 service drm /system/bin/drmserver
     class main
     user drm
@@ -578,10 +615,6 @@
     disabled
     oneshot
 
-service sshd /system/bin/start-ssh
-    class main
-    disabled
-
 service mdnsd /system/bin/mdnsd
     class main
     user mdnsr
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
new file mode 100644
index 0000000..75961e6
--- /dev/null
+++ b/rootdir/init.zygote32.rc
@@ -0,0 +1,8 @@
+service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
+    class main
+    socket zygote stream 660 root system
+    onrestart write /sys/android_power/request_state wake
+    onrestart write /sys/power/state on
+    onrestart restart media
+    onrestart restart netd
+
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
new file mode 100644
index 0000000..68c0668
--- /dev/null
+++ b/rootdir/init.zygote32_64.rc
@@ -0,0 +1,12 @@
+service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
+    class main
+    socket zygote stream 660 root system
+    onrestart write /sys/android_power/request_state wake
+    onrestart write /sys/power/state on
+    onrestart restart media
+    onrestart restart netd
+
+service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
+    class main
+    socket zygote_secondary stream 660 root system
+    onrestart restart zygote
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
new file mode 100644
index 0000000..afb6d63
--- /dev/null
+++ b/rootdir/init.zygote64.rc
@@ -0,0 +1,8 @@
+service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
+    class main
+    socket zygote stream 660 root system
+    onrestart write /sys/android_power/request_state wake
+    onrestart write /sys/power/state on
+    onrestart restart media
+    onrestart restart netd
+
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
new file mode 100644
index 0000000..979ab3b
--- /dev/null
+++ b/rootdir/init.zygote64_32.rc
@@ -0,0 +1,12 @@
+service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
+    class main
+    socket zygote stream 660 root system
+    onrestart write /sys/android_power/request_state wake
+    onrestart write /sys/power/state on
+    onrestart restart media
+    onrestart restart netd
+
+service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
+    class main
+    socket zygote_secondary stream 660 root system
+    onrestart restart zygote
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index b8fe716..eff24c3 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -91,3 +91,5 @@
 /sys/devices/virtual/input/input*   enable      0660  root   input
 /sys/devices/virtual/input/input*   poll_delay  0660  root   input
 /sys/devices/virtual/usb_composite/*   enable      0664  root   system
+/sys/devices/system/cpu/cpu*   cpufreq/scaling_max_freq   0664  system system
+/sys/devices/system/cpu/cpu*   cpufreq/scaling_min_freq   0664  system system
diff --git a/run-as/Android.mk b/run-as/Android.mk
index a8f2885..3774acc 100644
--- a/run-as/Android.mk
+++ b/run-as/Android.mk
@@ -1,10 +1,12 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:= run-as.c package.c
+LOCAL_SRC_FILES := run-as.c package.c
 
 LOCAL_SHARED_LIBRARIES := libselinux
 
-LOCAL_MODULE:= run-as
+LOCAL_MODULE := run-as
+
+LOCAL_CFLAGS := -Werror
 
 include $(BUILD_EXECUTABLE)
diff --git a/run-as/package.c b/run-as/package.c
index 901e9e3..4f8f3a7 100644
--- a/run-as/package.c
+++ b/run-as/package.c
@@ -128,7 +128,9 @@
     }
 
     /* Memory-map the file now */
-    address = TEMP_FAILURE_RETRY(mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0));
+    do {
+        address = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
+    } while (address == MAP_FAILED && errno == EINTR);
     if (address == MAP_FAILED) {
         address = NULL;
         goto EXIT;
@@ -408,10 +410,6 @@
         value = -1;
     }
     return value;
-
-BAD:
-    *pp = p;
-    return -1;
 }
 
 /* Read the system's package database and extract information about
diff --git a/sdcard/Android.mk b/sdcard/Android.mk
index 4630db9..63b0f41 100644
--- a/sdcard/Android.mk
+++ b/sdcard/Android.mk
@@ -1,10 +1,10 @@
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:= sdcard.c
-LOCAL_MODULE:= sdcard
-LOCAL_CFLAGS := -Wall -Wno-unused-parameter
+LOCAL_SRC_FILES := sdcard.c
+LOCAL_MODULE := sdcard
+LOCAL_CFLAGS := -Wall -Wno-unused-parameter -Werror
 
 LOCAL_SHARED_LIBRARIES := libc libcutils
 
diff --git a/sdcard/fuse.h b/sdcard/fuse.h
deleted file mode 100644
index 3138da9..0000000
--- a/sdcard/fuse.h
+++ /dev/null
@@ -1,578 +0,0 @@
-/*
-    FUSE: Filesystem in Userspace
-    Copyright (C) 2001-2008  Miklos Szeredi <miklos@szeredi.hu>
-
-    This program can be distributed under the terms of the GNU GPL.
-    See the file COPYING.
-*/
-
-/*
- * from the libfuse FAQ (and consistent with the Linux Kernel license):
- *
- * Under what conditions may I distribute a filesystem that uses the
- * raw kernel interface of FUSE?
- *
- * There are no restrictions whatsoever for using the raw kernel interface. 
- *
- */
-
-/*
- * This file defines the kernel interface of FUSE
- *
- * Protocol changelog:
- *
- * 7.9:
- *  - new fuse_getattr_in input argument of GETATTR
- *  - add lk_flags in fuse_lk_in
- *  - add lock_owner field to fuse_setattr_in, fuse_read_in and fuse_write_in
- *  - add blksize field to fuse_attr
- *  - add file flags field to fuse_read_in and fuse_write_in
- *
- * 7.10
- *  - add nonseekable open flag
- *
- * 7.11
- *  - add IOCTL message
- *  - add unsolicited notification support
- *  - add POLL message and NOTIFY_POLL notification
- *
- * 7.12
- *  - add umask flag to input argument of open, mknod and mkdir
- *  - add notification messages for invalidation of inodes and
- *    directory entries
- *
- * 7.13
- *  - make max number of background requests and congestion threshold
- *    tunables
- */
-
-#ifndef _LINUX_FUSE_H
-#define _LINUX_FUSE_H
-
-#include <linux/types.h>
-
-/*
- * Version negotiation:
- *
- * Both the kernel and userspace send the version they support in the
- * INIT request and reply respectively.
- *
- * If the major versions match then both shall use the smallest
- * of the two minor versions for communication.
- *
- * If the kernel supports a larger major version, then userspace shall
- * reply with the major version it supports, ignore the rest of the
- * INIT message and expect a new INIT message from the kernel with a
- * matching major version.
- *
- * If the library supports a larger major version, then it shall fall
- * back to the major protocol version sent by the kernel for
- * communication and reply with that major version (and an arbitrary
- * supported minor version).
- */
-
-/** Version number of this interface */
-#define FUSE_KERNEL_VERSION 7
-
-/** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 13
-
-/** The node ID of the root inode */
-#define FUSE_ROOT_ID 1
-
-/* Make sure all structures are padded to 64bit boundary, so 32bit
-   userspace works under 64bit kernels */
-
-struct fuse_attr {
-	__u64	ino;
-	__u64	size;
-	__u64	blocks;
-	__u64	atime;
-	__u64	mtime;
-	__u64	ctime;
-	__u32	atimensec;
-	__u32	mtimensec;
-	__u32	ctimensec;
-	__u32	mode;
-	__u32	nlink;
-	__u32	uid;
-	__u32	gid;
-	__u32	rdev;
-	__u32	blksize;
-	__u32	padding;
-};
-
-struct fuse_kstatfs {
-	__u64	blocks;
-	__u64	bfree;
-	__u64	bavail;
-	__u64	files;
-	__u64	ffree;
-	__u32	bsize;
-	__u32	namelen;
-	__u32	frsize;
-	__u32	padding;
-	__u32	spare[6];
-};
-
-struct fuse_file_lock {
-	__u64	start;
-	__u64	end;
-	__u32	type;
-	__u32	pid; /* tgid */
-};
-
-/**
- * Bitmasks for fuse_setattr_in.valid
- */
-#define FATTR_MODE	(1 << 0)
-#define FATTR_UID	(1 << 1)
-#define FATTR_GID	(1 << 2)
-#define FATTR_SIZE	(1 << 3)
-#define FATTR_ATIME	(1 << 4)
-#define FATTR_MTIME	(1 << 5)
-#define FATTR_FH	(1 << 6)
-#define FATTR_ATIME_NOW	(1 << 7)
-#define FATTR_MTIME_NOW	(1 << 8)
-#define FATTR_LOCKOWNER	(1 << 9)
-
-/**
- * Flags returned by the OPEN request
- *
- * FOPEN_DIRECT_IO: bypass page cache for this open file
- * FOPEN_KEEP_CACHE: don't invalidate the data cache on open
- * FOPEN_NONSEEKABLE: the file is not seekable
- */
-#define FOPEN_DIRECT_IO		(1 << 0)
-#define FOPEN_KEEP_CACHE	(1 << 1)
-#define FOPEN_NONSEEKABLE	(1 << 2)
-
-/**
- * INIT request/reply flags
- *
- * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
- * FUSE_DONT_MASK: don't apply umask to file mode on create operations
- */
-#define FUSE_ASYNC_READ		(1 << 0)
-#define FUSE_POSIX_LOCKS	(1 << 1)
-#define FUSE_FILE_OPS		(1 << 2)
-#define FUSE_ATOMIC_O_TRUNC	(1 << 3)
-#define FUSE_EXPORT_SUPPORT	(1 << 4)
-#define FUSE_BIG_WRITES		(1 << 5)
-#define FUSE_DONT_MASK		(1 << 6)
-
-/**
- * CUSE INIT request/reply flags
- *
- * CUSE_UNRESTRICTED_IOCTL:  use unrestricted ioctl
- */
-#define CUSE_UNRESTRICTED_IOCTL	(1 << 0)
-
-/**
- * Release flags
- */
-#define FUSE_RELEASE_FLUSH	(1 << 0)
-
-/**
- * Getattr flags
- */
-#define FUSE_GETATTR_FH		(1 << 0)
-
-/**
- * Lock flags
- */
-#define FUSE_LK_FLOCK		(1 << 0)
-
-/**
- * WRITE flags
- *
- * FUSE_WRITE_CACHE: delayed write from page cache, file handle is guessed
- * FUSE_WRITE_LOCKOWNER: lock_owner field is valid
- */
-#define FUSE_WRITE_CACHE	(1 << 0)
-#define FUSE_WRITE_LOCKOWNER	(1 << 1)
-
-/**
- * Read flags
- */
-#define FUSE_READ_LOCKOWNER	(1 << 1)
-
-/**
- * Ioctl flags
- *
- * FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine
- * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed
- * FUSE_IOCTL_RETRY: retry with new iovecs
- *
- * FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs
- */
-#define FUSE_IOCTL_COMPAT	(1 << 0)
-#define FUSE_IOCTL_UNRESTRICTED	(1 << 1)
-#define FUSE_IOCTL_RETRY	(1 << 2)
-
-#define FUSE_IOCTL_MAX_IOV	256
-
-/**
- * Poll flags
- *
- * FUSE_POLL_SCHEDULE_NOTIFY: request poll notify
- */
-#define FUSE_POLL_SCHEDULE_NOTIFY (1 << 0)
-
-enum fuse_opcode {
-	FUSE_LOOKUP	   = 1,
-	FUSE_FORGET	   = 2,  /* no reply */
-	FUSE_GETATTR	   = 3,
-	FUSE_SETATTR	   = 4,
-	FUSE_READLINK	   = 5,
-	FUSE_SYMLINK	   = 6,
-	FUSE_MKNOD	   = 8,
-	FUSE_MKDIR	   = 9,
-	FUSE_UNLINK	   = 10,
-	FUSE_RMDIR	   = 11,
-	FUSE_RENAME	   = 12,
-	FUSE_LINK	   = 13,
-	FUSE_OPEN	   = 14,
-	FUSE_READ	   = 15,
-	FUSE_WRITE	   = 16,
-	FUSE_STATFS	   = 17,
-	FUSE_RELEASE       = 18,
-	FUSE_FSYNC         = 20,
-	FUSE_SETXATTR      = 21,
-	FUSE_GETXATTR      = 22,
-	FUSE_LISTXATTR     = 23,
-	FUSE_REMOVEXATTR   = 24,
-	FUSE_FLUSH         = 25,
-	FUSE_INIT          = 26,
-	FUSE_OPENDIR       = 27,
-	FUSE_READDIR       = 28,
-	FUSE_RELEASEDIR    = 29,
-	FUSE_FSYNCDIR      = 30,
-	FUSE_GETLK         = 31,
-	FUSE_SETLK         = 32,
-	FUSE_SETLKW        = 33,
-	FUSE_ACCESS        = 34,
-	FUSE_CREATE        = 35,
-	FUSE_INTERRUPT     = 36,
-	FUSE_BMAP          = 37,
-	FUSE_DESTROY       = 38,
-	FUSE_IOCTL         = 39,
-	FUSE_POLL          = 40,
-
-	/* CUSE specific operations */
-	CUSE_INIT          = 4096,
-};
-
-enum fuse_notify_code {
-	FUSE_NOTIFY_POLL   = 1,
-	FUSE_NOTIFY_INVAL_INODE = 2,
-	FUSE_NOTIFY_INVAL_ENTRY = 3,
-	FUSE_NOTIFY_CODE_MAX,
-};
-
-/* The read buffer is required to be at least 8k, but may be much larger */
-#define FUSE_MIN_READ_BUFFER 8192
-
-#define FUSE_COMPAT_ENTRY_OUT_SIZE 120
-
-struct fuse_entry_out {
-	__u64	nodeid;		/* Inode ID */
-	__u64	generation;	/* Inode generation: nodeid:gen must
-				   be unique for the fs's lifetime */
-	__u64	entry_valid;	/* Cache timeout for the name */
-	__u64	attr_valid;	/* Cache timeout for the attributes */
-	__u32	entry_valid_nsec;
-	__u32	attr_valid_nsec;
-	struct fuse_attr attr;
-};
-
-struct fuse_forget_in {
-	__u64	nlookup;
-};
-
-struct fuse_getattr_in {
-	__u32	getattr_flags;
-	__u32	dummy;
-	__u64	fh;
-};
-
-#define FUSE_COMPAT_ATTR_OUT_SIZE 96
-
-struct fuse_attr_out {
-	__u64	attr_valid;	/* Cache timeout for the attributes */
-	__u32	attr_valid_nsec;
-	__u32	dummy;
-	struct fuse_attr attr;
-};
-
-#define FUSE_COMPAT_MKNOD_IN_SIZE 8
-
-struct fuse_mknod_in {
-	__u32	mode;
-	__u32	rdev;
-	__u32	umask;
-	__u32	padding;
-};
-
-struct fuse_mkdir_in {
-	__u32	mode;
-	__u32	umask;
-};
-
-struct fuse_rename_in {
-	__u64	newdir;
-};
-
-struct fuse_link_in {
-	__u64	oldnodeid;
-};
-
-struct fuse_setattr_in {
-	__u32	valid;
-	__u32	padding;
-	__u64	fh;
-	__u64	size;
-	__u64	lock_owner;
-	__u64	atime;
-	__u64	mtime;
-	__u64	unused2;
-	__u32	atimensec;
-	__u32	mtimensec;
-	__u32	unused3;
-	__u32	mode;
-	__u32	unused4;
-	__u32	uid;
-	__u32	gid;
-	__u32	unused5;
-};
-
-struct fuse_open_in {
-	__u32	flags;
-	__u32	unused;
-};
-
-struct fuse_create_in {
-	__u32	flags;
-	__u32	mode;
-	__u32	umask;
-	__u32	padding;
-};
-
-struct fuse_open_out {
-	__u64	fh;
-	__u32	open_flags;
-	__u32	padding;
-};
-
-struct fuse_release_in {
-	__u64	fh;
-	__u32	flags;
-	__u32	release_flags;
-	__u64	lock_owner;
-};
-
-struct fuse_flush_in {
-	__u64	fh;
-	__u32	unused;
-	__u32	padding;
-	__u64	lock_owner;
-};
-
-struct fuse_read_in {
-	__u64	fh;
-	__u64	offset;
-	__u32	size;
-	__u32	read_flags;
-	__u64	lock_owner;
-	__u32	flags;
-	__u32	padding;
-};
-
-#define FUSE_COMPAT_WRITE_IN_SIZE 24
-
-struct fuse_write_in {
-	__u64	fh;
-	__u64	offset;
-	__u32	size;
-	__u32	write_flags;
-	__u64	lock_owner;
-	__u32	flags;
-	__u32	padding;
-};
-
-struct fuse_write_out {
-	__u32	size;
-	__u32	padding;
-};
-
-#define FUSE_COMPAT_STATFS_SIZE 48
-
-struct fuse_statfs_out {
-	struct fuse_kstatfs st;
-};
-
-struct fuse_fsync_in {
-	__u64	fh;
-	__u32	fsync_flags;
-	__u32	padding;
-};
-
-struct fuse_setxattr_in {
-	__u32	size;
-	__u32	flags;
-};
-
-struct fuse_getxattr_in {
-	__u32	size;
-	__u32	padding;
-};
-
-struct fuse_getxattr_out {
-	__u32	size;
-	__u32	padding;
-};
-
-struct fuse_lk_in {
-	__u64	fh;
-	__u64	owner;
-	struct fuse_file_lock lk;
-	__u32	lk_flags;
-	__u32	padding;
-};
-
-struct fuse_lk_out {
-	struct fuse_file_lock lk;
-};
-
-struct fuse_access_in {
-	__u32	mask;
-	__u32	padding;
-};
-
-struct fuse_init_in {
-	__u32	major;
-	__u32	minor;
-	__u32	max_readahead;
-	__u32	flags;
-};
-
-struct fuse_init_out {
-	__u32	major;
-	__u32	minor;
-	__u32	max_readahead;
-	__u32	flags;
-	__u16   max_background;
-	__u16   congestion_threshold;
-	__u32	max_write;
-};
-
-#define CUSE_INIT_INFO_MAX 4096
-
-struct cuse_init_in {
-	__u32	major;
-	__u32	minor;
-	__u32	unused;
-	__u32	flags;
-};
-
-struct cuse_init_out {
-	__u32	major;
-	__u32	minor;
-	__u32	unused;
-	__u32	flags;
-	__u32	max_read;
-	__u32	max_write;
-	__u32	dev_major;		/* chardev major */
-	__u32	dev_minor;		/* chardev minor */
-	__u32	spare[10];
-};
-
-struct fuse_interrupt_in {
-	__u64	unique;
-};
-
-struct fuse_bmap_in {
-	__u64	block;
-	__u32	blocksize;
-	__u32	padding;
-};
-
-struct fuse_bmap_out {
-	__u64	block;
-};
-
-struct fuse_ioctl_in {
-	__u64	fh;
-	__u32	flags;
-	__u32	cmd;
-	__u64	arg;
-	__u32	in_size;
-	__u32	out_size;
-};
-
-struct fuse_ioctl_out {
-	__s32	result;
-	__u32	flags;
-	__u32	in_iovs;
-	__u32	out_iovs;
-};
-
-struct fuse_poll_in {
-	__u64	fh;
-	__u64	kh;
-	__u32	flags;
-	__u32   padding;
-};
-
-struct fuse_poll_out {
-	__u32	revents;
-	__u32	padding;
-};
-
-struct fuse_notify_poll_wakeup_out {
-	__u64	kh;
-};
-
-struct fuse_in_header {
-	__u32	len;
-	__u32	opcode;
-	__u64	unique;
-	__u64	nodeid;
-	__u32	uid;
-	__u32	gid;
-	__u32	pid;
-	__u32	padding;
-};
-
-struct fuse_out_header {
-	__u32	len;
-	__s32	error;
-	__u64	unique;
-};
-
-struct fuse_dirent {
-	__u64	ino;
-	__u64	off;
-	__u32	namelen;
-	__u32	type;
-	char name[0];
-};
-
-#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
-#define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(__u64) - 1) & ~(sizeof(__u64) - 1))
-#define FUSE_DIRENT_SIZE(d) \
-	FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
-
-struct fuse_notify_inval_inode_out {
-	__u64	ino;
-	__s64	off;
-	__s64	len;
-};
-
-struct fuse_notify_inval_entry_out {
-	__u64	parent;
-	__u32	namelen;
-	__u32	padding;
-};
-
-#endif /* _LINUX_FUSE_H */
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 05fbfba..844ca65 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -14,39 +14,41 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "sdcard"
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <linux/fuse.h>
+#include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
+#include <sys/inotify.h>
 #include <sys/mount.h>
+#include <sys/resource.h>
 #include <sys/stat.h>
 #include <sys/statfs.h>
-#include <sys/uio.h>
-#include <dirent.h>
-#include <limits.h>
-#include <ctype.h>
-#include <pthread.h>
 #include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/inotify.h>
+#include <sys/uio.h>
+#include <unistd.h>
 
 #include <cutils/fs.h>
 #include <cutils/hashmap.h>
+#include <cutils/log.h>
 #include <cutils/multiuser.h>
 
 #include <private/android_filesystem_config.h>
 
-#include "fuse.h"
-
 /* README
  *
  * What is this?
- * 
+ *
  * sdcard is a program that uses FUSE to emulate FAT-on-sdcard style
- * directory permissions (all files are given fixed owner, group, and 
- * permissions at creation, owner, group, and permissions are not 
+ * directory permissions (all files are given fixed owner, group, and
+ * permissions at creation, owner, group, and permissions are not
  * changeable, symlinks and hardlinks are not createable, etc.
  *
  * See usage() for command line options.
@@ -91,12 +93,12 @@
 #define FUSE_TRACE 0
 
 #if FUSE_TRACE
-#define TRACE(x...) fprintf(stderr,x)
+#define TRACE(x...) ALOGD(x)
 #else
 #define TRACE(x...) do {} while (0)
 #endif
 
-#define ERROR(x...) fprintf(stderr,x)
+#define ERROR(x...) ALOGE(x)
 
 #define FUSE_UNKNOWN_INO 0xffffffff
 
@@ -200,7 +202,7 @@
 }
 
 static int int_hash(void *key) {
-    return (int) key;
+    return (int) (uintptr_t) key;
 }
 
 static bool int_equals(void *keyA, void *keyB) {
@@ -232,7 +234,7 @@
      * buffer at the same time.  This allows us to share the underlying storage. */
     union {
         __u8 request_buffer[MAX_REQUEST_SIZE];
-        __u8 read_buffer[MAX_READ];
+        __u8 read_buffer[MAX_READ + PAGESIZE];
     };
 };
 
@@ -487,7 +489,7 @@
         break;
     case PERM_ANDROID_DATA:
     case PERM_ANDROID_OBB:
-        appid = (appid_t) hashmapGet(fuse->package_to_appid, node->name);
+        appid = (appid_t) (uintptr_t) hashmapGet(fuse->package_to_appid, node->name);
         if (appid != 0) {
             node->uid = multiuser_get_uid(parent->userid, appid);
         }
@@ -511,7 +513,7 @@
     }
 
     appid_t appid = multiuser_get_app_id(hdr->uid);
-    return hashmapContainsKey(fuse->appid_with_rw, (void*) appid);
+    return hashmapContainsKey(fuse->appid_with_rw, (void*) (uintptr_t) appid);
 }
 
 /* Kernel has already enforced everything we returned through
@@ -1218,6 +1220,7 @@
     __u32 size = req->size;
     __u64 offset = req->offset;
     int res;
+    __u8 *read_buffer = (__u8 *) ((uintptr_t)(handler->read_buffer + PAGESIZE) & ~((uintptr_t)PAGESIZE-1));
 
     /* Don't access any other fields of hdr or req beyond this point, the read buffer
      * overlaps the request buffer and will clobber data in the request.  This
@@ -1225,14 +1228,14 @@
 
     TRACE("[%d] READ %p(%d) %u@%llu\n", handler->token,
             h, h->fd, size, offset);
-    if (size > sizeof(handler->read_buffer)) {
+    if (size > MAX_READ) {
         return -EINVAL;
     }
-    res = pread64(h->fd, handler->read_buffer, size, offset);
+    res = pread64(h->fd, read_buffer, size, offset);
     if (res < 0) {
         return -errno;
     }
-    fuse_reply(fuse, unique, handler->read_buffer, res);
+    fuse_reply(fuse, unique, read_buffer, res);
     return NO_STATUS;
 }
 
@@ -1243,6 +1246,12 @@
     struct fuse_write_out out;
     struct handle *h = id_to_ptr(req->fh);
     int res;
+    __u8 aligned_buffer[req->size] __attribute__((__aligned__(PAGESIZE)));
+
+    if (req->flags & O_DIRECT) {
+        memcpy(aligned_buffer, buffer, req->size);
+        buffer = (const __u8*) aligned_buffer;
+    }
 
     TRACE("[%d] WRITE %p(%d) %u@%llu\n", handler->token,
             h, h->fd, req->size, req->offset);
@@ -1300,14 +1309,23 @@
 static int handle_fsync(struct fuse* fuse, struct fuse_handler* handler,
         const struct fuse_in_header* hdr, const struct fuse_fsync_in* req)
 {
-    int is_data_sync = req->fsync_flags & 1;
-    struct handle *h = id_to_ptr(req->fh);
-    int res;
+    bool is_dir = (hdr->opcode == FUSE_FSYNCDIR);
+    bool is_data_sync = req->fsync_flags & 1;
 
-    TRACE("[%d] FSYNC %p(%d) is_data_sync=%d\n", handler->token,
-            h, h->fd, is_data_sync);
-    res = is_data_sync ? fdatasync(h->fd) : fsync(h->fd);
-    if (res < 0) {
+    int fd = -1;
+    if (is_dir) {
+      struct dirhandle *dh = id_to_ptr(req->fh);
+      fd = dirfd(dh->d);
+    } else {
+      struct handle *h = id_to_ptr(req->fh);
+      fd = h->fd;
+    }
+
+    TRACE("[%d] %s %p(%d) is_data_sync=%d\n", handler->token,
+            is_dir ? "FSYNCDIR" : "FSYNC",
+            id_to_ptr(req->fh), fd, is_data_sync);
+    int res = is_data_sync ? fdatasync(fd) : fsync(fd);
+    if (res == -1) {
         return -errno;
     }
     return 0;
@@ -1496,7 +1514,8 @@
         return handle_release(fuse, handler, hdr, req);
     }
 
-    case FUSE_FSYNC: {
+    case FUSE_FSYNC:
+    case FUSE_FSYNCDIR: {
         const struct fuse_fsync_in *req = data;
         return handle_fsync(fuse, handler, hdr, req);
     }
@@ -1524,7 +1543,6 @@
         return handle_releasedir(fuse, handler, hdr, req);
     }
 
-//    case FUSE_FSYNCDIR:
     case FUSE_INIT: { /* init_in -> init_out */
         const struct fuse_init_in *req = data;
         return handle_init(fuse, handler, hdr, req);
@@ -1621,12 +1639,12 @@
 
         if (sscanf(buf, "%s %d %*d %*s %*s %s", package_name, &appid, gids) == 3) {
             char* package_name_dup = strdup(package_name);
-            hashmapPut(fuse->package_to_appid, package_name_dup, (void*) appid);
+            hashmapPut(fuse->package_to_appid, package_name_dup, (void*) (uintptr_t) appid);
 
             char* token = strtok(gids, ",");
             while (token != NULL) {
                 if (strtoul(token, NULL, 10) == fuse->write_gid) {
-                    hashmapPut(fuse->appid_with_rw, (void*) appid, (void*) 1);
+                    hashmapPut(fuse->appid_with_rw, (void*) (uintptr_t) appid, (void*) (uintptr_t) 1);
                     break;
                 }
                 token = strtok(NULL, ",");
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 4fff9f5..c53f17d 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -2,73 +2,75 @@
 include $(CLEAR_VARS)
 
 TOOLS := \
-	ls \
-	mount \
 	cat \
-	ps \
-	kill \
-	ln \
-	insmod \
-	rmmod \
-	lsmod \
-	ifconfig \
-	rm \
-	mkdir \
-	rmdir \
-	getevent \
-	sendevent \
-	date \
-	wipe \
-	sync \
-	umount \
-	start \
-	stop \
-	notify \
-	cmp \
-	dmesg \
-	route \
-	hd \
-	dd \
-	df \
-	getprop \
-	setprop \
-	watchprops \
-	log \
-	sleep \
-	renice \
-	printenv \
-	smd \
+	chcon \
 	chmod \
 	chown \
-	newfs_msdos \
-	netstat \
-	ioctl \
-	mv \
-	schedtop \
-	top \
-	iftop \
+	clear \
+	cmp \
+	date \
+	dd \
+	df \
+	dmesg \
+	du \
+	getenforce \
+	getevent \
+	getprop \
+	getsebool \
+	hd \
 	id \
+	ifconfig \
+	iftop \
+	insmod \
+	ioctl \
+	ionice \
+	kill \
+	ln \
+	load_policy \
+	log \
+	ls \
+	lsmod \
+	lsof \
+	md5 \
+	mkdir \
+	mknod \
+	mkswap \
+	mount \
+	mv \
+	nandread \
+	netstat \
+	newfs_msdos \
+	nohup \
+	notify \
+	printenv \
+	ps \
+	readlink \
+	renice \
+	restorecon \
+	rm \
+	rmdir \
+	rmmod \
+	route \
+	runcon \
+	schedtop \
+	sendevent \
+	setenforce \
+	setprop \
+	setsebool \
+	sleep \
+	smd \
+	start \
+	stop \
+	swapoff \
+	swapon \
+	sync \
+	top \
+	touch \
+	umount \
 	uptime \
 	vmstat \
-	nandread \
-	ionice \
-	touch \
-	lsof \
-	du \
-	md5 \
-	clear \
-	getenforce \
-	setenforce \
-	chcon \
-	restorecon \
-	runcon \
-	getsebool \
-	setsebool \
-	load_policy \
-	swapon \
-	swapoff \
-	mkswap \
-	readlink
+	watchprops \
+	wipe \
 
 ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
 TOOLS += r
@@ -80,24 +82,37 @@
 	grep
 
 LOCAL_SRC_FILES := \
+	cp/cp.c \
+	cp/utils.c \
 	dynarray.c \
-	toolbox.c \
+	grep/fastgrep.c \
+	grep/file.c \
+	grep/grep.c \
+	grep/queue.c \
+	grep/util.c \
 	$(patsubst %,%.c,$(TOOLS)) \
-	cp/cp.c cp/utils.c \
-	grep/grep.c grep/fastgrep.c grep/file.c grep/queue.c grep/util.c
+	toolbox.c \
+	uid_from_user.c \
 
-LOCAL_C_INCLUDES := bionic/libc/bionic
+LOCAL_CFLAGS += \
+    -std=gnu99 \
+    -Werror -Wno-unused-parameter \
+    -include bsd-compatibility.h \
 
-LOCAL_CFLAGS += -Wno-unused-parameter
+LOCAL_C_INCLUDES += external/openssl/include
 
 LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-	liblog \
-	libc \
-	libusbhost \
-	libselinux
+    libcrypto \
+    libcutils \
+    libselinux \
+
+# libusbhost is only used by lsusb, and that isn't usually included in toolbox.
+# The linker strips out all the unused library code in the normal case.
+LOCAL_STATIC_LIBRARIES := \
+    libusbhost \
 
 LOCAL_MODULE := toolbox
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 
 # Including this will define $(intermediates).
 #
diff --git a/toolbox/bsd-compatibility.h b/toolbox/bsd-compatibility.h
new file mode 100644
index 0000000..a304631
--- /dev/null
+++ b/toolbox/bsd-compatibility.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014, 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.
+ *
+ * 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 <sys/types.h>
+
+/* We want chown to support user.group as well as user:group. */
+#define SUPPORT_DOT
+
+__BEGIN_DECLS
+
+extern int uid_from_user(const char* name, uid_t* uid);
+
+__END_DECLS
diff --git a/toolbox/chown.c b/toolbox/chown.c
index 92efee6..6ac2233 100644
--- a/toolbox/chown.c
+++ b/toolbox/chown.c
@@ -1,73 +1,302 @@
+/*	$NetBSD: chown.c,v 1.8 2012/10/24 01:12:51 enami Exp $	*/
+
+/*
+ * Copyright (c) 1988, 1993, 1994, 2003
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * 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 University 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 REGENTS 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 REGENTS 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 <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994, 2003\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)chown.c	8.8 (Berkeley) 4/4/94";
+#else
+__RCSID("$NetBSD: chown.c,v 1.8 2012/10/24 01:12:51 enami Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <locale.h>
+#include <fts.h>
+#include <grp.h>
+#include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <errno.h>
-#include <pwd.h>
-#include <grp.h>
-
 #include <unistd.h>
-#include <time.h>
+#include <getopt.h>
 
-int chown_main(int argc, char **argv)
+static void	a_gid(const char *);
+static void	a_uid(const char *);
+static id_t	id(const char *, const char *);
+__dead static void	usage(void);
+
+static uid_t uid;
+static gid_t gid;
+static int ischown;
+static const char *myname;
+
+struct option chown_longopts[] = {
+	{ "reference",		required_argument,	0,
+						1 },
+	{ NULL,			0,			0,
+						0 },
+};
+
+int
+chown_main(int argc, char **argv)
 {
-    int i;
+	FTS *ftsp;
+	FTSENT *p;
+	int Hflag, Lflag, Rflag, ch, fflag, fts_options, hflag, rval, vflag;
+	char *cp, *reference;
+	int (*change_owner)(const char *, uid_t, gid_t);
 
-    if (argc < 3) {
-        fprintf(stderr, "Usage: chown <USER>[:GROUP] <FILE1> [FILE2] ...\n");
-        return 10;
-    }
+	setprogname(*argv);
 
-    // Copy argv[1] to 'user' so we can truncate it at the period
-    // if a group id specified.
-    char user[32];
-    char *group = NULL;
-    strncpy(user, argv[1], sizeof(user));
-    if ((group = strchr(user, ':')) != NULL) {
-        *group++ = '\0';
-    } else if ((group = strchr(user, '.')) != NULL) {
-        *group++ = '\0';
-    }
+	(void)setlocale(LC_ALL, "");
 
-    // Lookup uid (and gid if specified)
-    struct passwd *pw;
-    struct group *grp = NULL;
-    uid_t uid;
-    gid_t gid = -1; // passing -1 to chown preserves current group
+	myname = getprogname();
+	ischown = (myname[2] == 'o');
+	reference = NULL;
 
-    pw = getpwnam(user);
-    if (pw != NULL) {
-        uid = pw->pw_uid;
-    } else {
-        char* endptr;
-        uid = (int) strtoul(user, &endptr, 0);
-        if (endptr == user) {  // no conversion
-          fprintf(stderr, "No such user '%s'\n", user);
-          return 10;
-        }
-    }
+	Hflag = Lflag = Rflag = fflag = hflag = vflag = 0;
+	while ((ch = getopt_long(argc, argv, "HLPRfhv",
+	    chown_longopts, NULL)) != -1)
+		switch (ch) {
+		case 1:
+			reference = optarg;
+			break;
+		case 'H':
+			Hflag = 1;
+			Lflag = 0;
+			break;
+		case 'L':
+			Lflag = 1;
+			Hflag = 0;
+			break;
+		case 'P':
+			Hflag = Lflag = 0;
+			break;
+		case 'R':
+			Rflag = 1;
+			break;
+		case 'f':
+			fflag = 1;
+			break;
+		case 'h':
+			/*
+			 * In System V the -h option causes chown/chgrp to
+			 * change the owner/group of the symbolic link.
+			 * 4.4BSD's symbolic links didn't have owners/groups,
+			 * so it was an undocumented noop.
+			 * In NetBSD 1.3, lchown(2) is introduced.
+			 */
+			hflag = 1;
+			break;
+		case 'v':
+			vflag = 1;
+			break;
+		case '?':
+		default:
+			usage();
+		}
+	argv += optind;
+	argc -= optind;
 
-    if (group != NULL) {
-        grp = getgrnam(group);
-        if (grp != NULL) {
-            gid = grp->gr_gid;
-        } else {
-            char* endptr;
-            gid = (int) strtoul(group, &endptr, 0);
-            if (endptr == group) {  // no conversion
-                fprintf(stderr, "No such group '%s'\n", group);
-                return 10;
-            }
-        }
-    }
+	if (argc == 0 || (argc == 1 && reference == NULL))
+		usage();
 
-    for (i = 2; i < argc; i++) {
-        if (chown(argv[i], uid, gid) < 0) {
-            fprintf(stderr, "Unable to chown %s: %s\n", argv[i], strerror(errno));
-            return 10;
-        }
-    }
+	fts_options = FTS_PHYSICAL;
+	if (Rflag) {
+		if (Hflag)
+			fts_options |= FTS_COMFOLLOW;
+		if (Lflag) {
+			if (hflag)
+				errx(EXIT_FAILURE,
+				    "the -L and -h options "
+				    "may not be specified together.");
+			fts_options &= ~FTS_PHYSICAL;
+			fts_options |= FTS_LOGICAL;
+		}
+	} else if (!hflag)
+		fts_options |= FTS_COMFOLLOW;
 
-    return 0;
+	uid = (uid_t)-1;
+	gid = (gid_t)-1;
+	if (reference == NULL) {
+		if (ischown) {
+			if ((cp = strchr(*argv, ':')) != NULL) {
+				*cp++ = '\0';
+				a_gid(cp);
+			}
+#ifdef SUPPORT_DOT
+			else if ((cp = strrchr(*argv, '.')) != NULL) {
+				if (uid_from_user(*argv, &uid) == -1) {
+					*cp++ = '\0';
+					a_gid(cp);
+				}
+			}
+#endif
+			a_uid(*argv);
+		} else
+			a_gid(*argv);
+		argv++;
+	} else {
+		struct stat st;
+
+		if (stat(reference, &st) == -1)
+			err(EXIT_FAILURE, "Cannot stat `%s'", reference);
+		if (ischown)
+			uid = st.st_uid;
+		gid = st.st_gid;
+	}
+
+	if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL)
+		err(EXIT_FAILURE, "fts_open");
+
+	for (rval = EXIT_SUCCESS; (p = fts_read(ftsp)) != NULL;) {
+		change_owner = chown;
+		switch (p->fts_info) {
+		case FTS_D:
+			if (!Rflag)		/* Change it at FTS_DP. */
+				fts_set(ftsp, p, FTS_SKIP);
+			continue;
+		case FTS_DNR:			/* Warn, chown, continue. */
+			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+			rval = EXIT_FAILURE;
+			break;
+		case FTS_ERR:			/* Warn, continue. */
+		case FTS_NS:
+			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+			rval = EXIT_FAILURE;
+			continue;
+		case FTS_SL:			/* Ignore unless -h. */
+			/*
+			 * All symlinks we found while doing a physical
+			 * walk end up here.
+			 */
+			if (!hflag)
+				continue;
+			/*
+			 * Note that if we follow a symlink, fts_info is
+			 * not FTS_SL but FTS_F or whatever.  And we should
+			 * use lchown only for FTS_SL and should use chown
+			 * for others.
+			 */
+			change_owner = lchown;
+			break;
+		case FTS_SLNONE:		/* Ignore. */
+			/*
+			 * The only symlinks that end up here are ones that
+			 * don't point to anything.  Note that if we are
+			 * doing a phisycal walk, we never reach here unless
+			 * we asked to follow explicitly.
+			 */
+			continue;
+		default:
+			break;
+		}
+
+		if ((*change_owner)(p->fts_accpath, uid, gid) && !fflag) {
+			warn("%s", p->fts_path);
+			rval = EXIT_FAILURE;
+		} else {
+			if (vflag)
+				printf("%s\n", p->fts_path);
+		}
+	}
+	if (errno)
+		err(EXIT_FAILURE, "fts_read");
+	exit(rval);
+	/* NOTREACHED */
+}
+
+static void
+a_gid(const char *s)
+{
+	struct group *gr;
+
+	if (*s == '\0')			/* Argument was "uid[:.]". */
+		return;
+	gr = *s == '#' ? NULL : getgrnam(s);
+	if (gr == NULL)
+		gid = id(s, "group");
+	else
+		gid = gr->gr_gid;
+	return;
+}
+
+static void
+a_uid(const char *s)
+{
+	if (*s == '\0')			/* Argument was "[:.]gid". */
+		return;
+	if (*s == '#' || uid_from_user(s, &uid) == -1) {
+		uid = id(s, "user");
+	}
+	return;
+}
+
+static id_t
+id(const char *name, const char *type)
+{
+	id_t val;
+	char *ep;
+
+	errno = 0;
+	if (*name == '#')
+		name++;
+	val = (id_t)strtoul(name, &ep, 10);
+	if (errno)
+		err(EXIT_FAILURE, "%s", name);
+	if (*ep != '\0')
+		errx(EXIT_FAILURE, "%s: invalid %s name", name, type);
+	return (val);
+}
+
+static void
+usage(void)
+{
+
+	(void)fprintf(stderr,
+	    "Usage: %s [-R [-H | -L | -P]] [-fhv] %s file ...\n"
+	    "\t%s [-R [-H | -L | -P]] [-fhv] --reference=rfile file ...\n",
+	    myname, ischown ? "owner:group|owner|:group" : "group",
+	    myname);
+	exit(EXIT_FAILURE);
 }
diff --git a/toolbox/cp/cp.c b/toolbox/cp/cp.c
index bd3c70e..e666453 100644
--- a/toolbox/cp/cp.c
+++ b/toolbox/cp/cp.c
@@ -95,12 +95,14 @@
 
 static int copy(char *[], enum op, int);
 
+#ifndef ANDROID
 static void
 progress(int sig __unused)
 {
 
 	pinfo++;
 }
+#endif
 
 int
 cp_main(int argc, char *argv[])
diff --git a/toolbox/cp/utils.c b/toolbox/cp/utils.c
index b682bbe..9d0390f 100644
--- a/toolbox/cp/utils.c
+++ b/toolbox/cp/utils.c
@@ -380,10 +380,11 @@
 int
 setfile(struct stat *fs, int fd)
 {
-	int rval, islink;
+	int rval = 0;
+#ifndef ANDROID
+	int islink = S_ISLNK(fs->st_mode);
+#endif
 
-	rval = 0;
-	islink = S_ISLNK(fs->st_mode);
 	fs->st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
 
 	/*
@@ -401,13 +402,13 @@
 		fs->st_mode &= ~(S_ISUID | S_ISGID);
 	}
 #ifdef ANDROID
-    if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) {
+        if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) {
 #else
-    if (fd ? fchmod(fd, fs->st_mode) : lchmod(to.p_path, fs->st_mode)) {
+        if (fd ? fchmod(fd, fs->st_mode) : lchmod(to.p_path, fs->st_mode)) {
 #endif
-        warn("chmod: %s", to.p_path);
-        rval = 1;
-    }
+                warn("chmod: %s", to.p_path);
+                rval = 1;
+        }
 
 #ifndef ANDROID
 	if (!islink && !Nflag) {
diff --git a/toolbox/date.c b/toolbox/date.c
index d6c9052..70ce1d5 100644
--- a/toolbox/date.c
+++ b/toolbox/date.c
@@ -1,10 +1,13 @@
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
 #include <string.h>
-#include <errno.h>
 #include <time.h>
+#include <unistd.h>
+
 #include <linux/android_alarm.h>
 #include <linux/rtc.h>
 #include <sys/ioctl.h>
@@ -108,16 +111,41 @@
         settime_rtc_tm(&tm);
 }
 
+static char *parse_time(const char *str, struct timeval *ts) {
+  char *s;
+  long fs = 0; /* fractional seconds */
+
+  ts->tv_sec = strtoumax(str, &s, 10);
+
+  if (*s == '.') {
+    s++;
+    int count = 0;
+
+    /* read up to 6 digits (microseconds) */
+    while (*s && isdigit(*s)) {
+      if (++count < 7) {
+        fs = fs*10 + (*s - '0');
+      }
+      s++;
+    }
+
+    for (; count < 6; count++) {
+      fs *= 10;
+    }
+  }
+
+  ts->tv_usec = fs;
+  return s;
+}
+
 int date_main(int argc, char *argv[])
 {
-	int c;
+    int c;
     int res;
-	struct tm tm;
-	time_t t;
-	struct timeval tv;
-    struct timespec ts;
-	char strbuf[260];
-    int fd;
+    struct tm tm;
+    time_t t;
+    struct timeval tv;
+    char strbuf[260];
 
     int useutc = 0;
 
@@ -147,7 +175,6 @@
 
     int hasfmt = argc == optind + 1 && argv[optind][0] == '+';
     if(optind == argc || hasfmt) {
-        char buf[2000];
         time(&t);
         if (useutc) {
             gmtime_r(&t, &tm);
@@ -181,7 +208,7 @@
         //strptime(argv[optind], NULL, &tm);
         //tv.tv_sec = mktime(&tm);
         //tv.tv_usec = 0;
-        strtotimeval(argv[optind], &tv);
+        parse_time(argv[optind], &tv);
         printf("time %s -> %lu.%lu\n", argv[optind], tv.tv_sec, tv.tv_usec);
         res = settime_alarm_timeval(&tv);
         if (res < 0)
diff --git a/toolbox/dd.c b/toolbox/dd.c
index 6b61ffb..408a496 100644
--- a/toolbox/dd.c
+++ b/toolbox/dd.c
@@ -356,7 +356,7 @@
 			++st.in_full;
 
 		/* Handle full input blocks. */
-		} else if (n == in.dbsz) {
+		} else if (n == (int64_t)in.dbsz) {
 			in.dbcnt += in.dbrcnt = n;
 			++st.in_full;
 
@@ -521,7 +521,7 @@
 			outp += nw;
 			st.bytes += nw;
 			if (nw == n) {
-				if (n != out.dbsz)
+				if (n != (int64_t)out.dbsz)
 					++st.out_part;
 				else
 					++st.out_full;
@@ -649,8 +649,8 @@
 void
 pos_out(void)
 {
-//	struct mtop t_op;
-	int cnt, n;
+/*	struct mtop t_op;        */
+	int64_t cnt, n;
 
 	/*
 	 * If not a tape, try seeking on the file.  Seeking on a pipe is
@@ -681,7 +681,7 @@
 	}
 
 	/* Read it. */
-	for (cnt = 0; cnt < out.offset; ++cnt) {
+	for (cnt = 0; cnt < (int64_t)out.offset; ++cnt) {
 		if ((n = read(out.fd, out.db, out.dbsz)) > 0)
 			continue;
 
@@ -705,8 +705,8 @@
 			/* NOTREACHED */
 		}
 
-		while (cnt++ < out.offset)
-			if ((n = bwrite(out.fd, out.db, out.dbsz)) != out.dbsz) {
+		while (cnt++ < (int64_t)out.offset)
+			if ((n = bwrite(out.fd, out.db, out.dbsz)) != (int64_t)out.dbsz) {
 				fprintf(stderr, "%s: cannot position "
 					"by writing: %s\n",
 					out.name, strerror(errno));
@@ -1153,7 +1153,7 @@
 	    ((const struct arg *)b)->name));
 }
 
-static long long strsuftoll(const char* name, const char* arg, int def, unsigned int max)
+static long long strsuftoll(const char* name, const char* arg, int def, unsigned long long max)
 {
 	long long result;
 	
@@ -1180,7 +1180,7 @@
 f_count(char *arg)
 {
 
-	cpy_cnt = strsuftoll("block count", arg, 0, LLONG_MAX);
+	cpy_cnt = (uint64_t)strsuftoll("block count", arg, 0, 0xFFFFFFFFFFFFFFFFULL);
 	if (!cpy_cnt)
 		terminate(0);
 }
@@ -1228,14 +1228,14 @@
 f_seek(char *arg)
 {
 
-	out.offset = strsuftoll("seek blocks", arg, 0, LLONG_MAX);
+	out.offset = (uint64_t)strsuftoll("seek blocks", arg, 0, 0xFFFFFFFFFFFFFFFFULL);
 }
 
 static void
 f_skip(char *arg)
 {
 
-	in.offset = strsuftoll("skip blocks", arg, 0, LLONG_MAX);
+	in.offset = (uint64_t)strsuftoll("skip blocks", arg, 0, 0xFFFFFFFFFFFFFFFFULL);
 }
 
 static void
diff --git a/toolbox/du.c b/toolbox/du.c
index fc7c943..c8beba5 100644
--- a/toolbox/du.c
+++ b/toolbox/du.c
@@ -76,7 +76,7 @@
 	int64_t totalblocks;
 	int ftsoptions, listfiles;
 	int depth;
-	int Hflag, Lflag, aflag, ch, cflag, dflag, gkmflag, nflag, rval, sflag;
+	int Hflag, Lflag, aflag, ch, cflag, dflag, gkmflag, rval, sflag;
 	const char *noargv[2];
 
 	Hflag = Lflag = aflag = cflag = dflag = gkmflag = sflag = 0;
diff --git a/toolbox/getevent.c b/toolbox/getevent.c
index ed381f5..da83ec3 100644
--- a/toolbox/getevent.c
+++ b/toolbox/getevent.c
@@ -295,6 +295,7 @@
 {
     int version;
     int fd;
+    int clkid = CLOCK_MONOTONIC;
     struct pollfd *new_ufds;
     char **new_device_names;
     char name[80];
@@ -335,6 +336,11 @@
         idstr[0] = '\0';
     }
 
+    if (ioctl(fd, EVIOCSCLOCKID, &clkid) != 0) {
+        fprintf(stderr, "Can't enable monotonic clock reporting: %s\n", strerror(errno));
+        // a non-fatal error
+    }
+
     new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1));
     if(new_ufds == NULL) {
         fprintf(stderr, "out of memory\n");
@@ -470,9 +476,9 @@
     return 0;
 }
 
-static void usage(int argc, char *argv[])
+static void usage(char *name)
 {
-    fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]\n", argv[0]);
+    fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]\n", name);
     fprintf(stderr, "    -t: show time stamps\n");
     fprintf(stderr, "    -n: don't print newlines\n");
     fprintf(stderr, "    -s: print switch states for given bits\n");
@@ -492,13 +498,11 @@
     int c;
     int i;
     int res;
-    int pollres;
     int get_time = 0;
     int print_device = 0;
     char *newline = "\n";
     uint16_t get_switch = 0;
     struct input_event event;
-    int version;
     int print_flags = 0;
     int print_flags_set = 0;
     int dont_block = -1;
@@ -570,7 +574,7 @@
             fprintf(stderr, "%s: invalid option -%c\n",
                 argv[0], optopt);
         case 'h':
-            usage(argc, argv);
+            usage(argv[0]);
             exit(1);
         }
     } while (1);
@@ -582,7 +586,7 @@
         optind++;
     }
     if (optind != argc) {
-        usage(argc, argv);
+        usage(argv[0]);
         exit(1);
     }
     nfds = 1;
@@ -629,7 +633,8 @@
         return 0;
 
     while(1) {
-        pollres = poll(ufds, nfds, -1);
+        //int pollres =
+        poll(ufds, nfds, -1);
         //printf("poll %d, returned %d\n", nfds, pollres);
         if(ufds[0].revents & POLLIN) {
             read_notify(device_path, ufds[0].fd, print_flags);
diff --git a/toolbox/getevent.h b/toolbox/getevent.h
index 2b76209..0482d04 100644
--- a/toolbox/getevent.h
+++ b/toolbox/getevent.h
@@ -652,6 +652,7 @@
         LABEL_END,
 };
 
+#if 0
 static struct label id_labels[] = {
         LABEL(ID_BUS),
         LABEL(ID_VENDOR),
@@ -682,6 +683,7 @@
         LABEL(BUS_SPI),
         LABEL_END,
 };
+#endif
 
 static struct label mt_tool_labels[] = {
         LABEL(MT_TOOL_FINGER),
diff --git a/toolbox/getprop.c b/toolbox/getprop.c
index c001fda..dcc0ea0 100644
--- a/toolbox/getprop.c
+++ b/toolbox/getprop.c
@@ -3,7 +3,6 @@
 
 #include <cutils/properties.h>
 
-#include <sys/system_properties.h>
 #include "dynarray.h"
 
 static void record_prop(const char* key, const char* name, void* opaque)
@@ -31,12 +30,8 @@
     strlist_done(list);
 }
 
-int __system_property_wait(prop_info *pi);
-
 int getprop_main(int argc, char *argv[])
 {
-    int n = 0;
-
     if (argc == 1) {
         list_properties();
     } else {
diff --git a/toolbox/grep/file.c b/toolbox/grep/file.c
index 86b7658..d28dff5 100644
--- a/toolbox/grep/file.c
+++ b/toolbox/grep/file.c
@@ -78,7 +78,9 @@
 grep_refill(struct file *f)
 {
 	ssize_t nr;
+#ifndef ANDROID
 	int bzerr;
+#endif
 
 	bufpos = buffer;
 	bufrem = 0;
diff --git a/toolbox/grep/grep.c b/toolbox/grep/grep.c
index b5bb2ef..7b2c487 100644
--- a/toolbox/grep/grep.c
+++ b/toolbox/grep/grep.c
@@ -294,10 +294,8 @@
 		err(2, "%s", fn);
 	line = NULL;
 	len = 0;
-#ifndef ANDROID
 	while ((rlen = getline(&line, &len, f)) != -1)
 		add_pattern(line, *line == '\n' ? 0 : (size_t)rlen);
-#endif
 	free(line);
 	if (ferror(f))
 		err(2, "%s", fn);
@@ -405,7 +403,7 @@
 				Aflag = 0;
 			else if (Aflag > LLONG_MAX / 10) {
 				errno = ERANGE;
-				err(2, NULL);
+				err(2, "%llu", Aflag);
 			}
 			Aflag = Bflag = (Aflag * 10) + (c - '0');
 			break;
@@ -422,10 +420,10 @@
 			l = strtoull(optarg, &ep, 10);
 			if (((errno == ERANGE) && (l == ULLONG_MAX)) ||
 			    ((errno == EINVAL) && (l == 0)))
-				err(2, NULL);
+				err(2, "strtoull");
 			else if (ep[0] != '\0') {
 				errno = EINVAL;
-				err(2, NULL);
+				err(2, "empty");
 			}
 			if (c == 'A')
 				Aflag = l;
@@ -511,10 +509,10 @@
 			mcount = strtoull(optarg, &ep, 10);
 			if (((errno == ERANGE) && (mcount == ULLONG_MAX)) ||
 			    ((errno == EINVAL) && (mcount == 0)))
-				err(2, NULL);
+				err(2, "strtoull");
 			else if (ep[0] != '\0') {
 				errno = EINVAL;
-				err(2, NULL);
+				err(2, "empty");
 			}
 			break;
 		case 'n':
diff --git a/toolbox/grep/util.c b/toolbox/grep/util.c
index 497db06..5712fee 100644
--- a/toolbox/grep/util.c
+++ b/toolbox/grep/util.c
@@ -273,7 +273,7 @@
 	return (c);
 }
 
-#define iswword(x)	(iswalnum((x)) || (x) == L'_')
+#define iswword(x)	(iswalnum((wint_t)(x)) || (x) == L'_')
 
 /*
  * Processes a line comparing it with the specified patterns.  Each pattern
@@ -323,7 +323,7 @@
 				continue;
 			/* Check for whole word match */
 			if (fg_pattern[i].word && pmatch.rm_so != 0) {
-				wint_t wbegin, wend;
+				wchar_t wbegin, wend;
 
 				wbegin = wend = L' ';
 				if (pmatch.rm_so != 0 &&
diff --git a/toolbox/hd.c b/toolbox/hd.c
index 0d2f96a..7c9998e 100644
--- a/toolbox/hd.c
+++ b/toolbox/hd.c
@@ -14,7 +14,6 @@
 	unsigned char buf[4096];
     int res;
 	int read_len;
-	int rv = 0;
 	int i;
 	int filepos = 0;
 	int sum;
diff --git a/toolbox/ifconfig.c b/toolbox/ifconfig.c
index 80c0e5c..b953176 100644
--- a/toolbox/ifconfig.c
+++ b/toolbox/ifconfig.c
@@ -61,11 +61,11 @@
 {
     struct ifreq ifr;
     int s;
-    unsigned int addr, mask, flags;
+    unsigned int flags;
     char astring[20];
     char mstring[20];
     char *updown, *brdcst, *loopbk, *ppp, *running, *multi;
-    
+
     argc--;
     argv++;
 
@@ -85,13 +85,17 @@
             perror(ifr.ifr_name);
             return -1;
         } else
-            addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
+            strlcpy(astring,
+                   inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr),
+                   sizeof(astring));
 
         if (ioctl(s, SIOCGIFNETMASK, &ifr) < 0) {
             perror(ifr.ifr_name);
             return -1;
         } else
-            mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
+            strlcpy(mstring,
+                   inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr),
+                   sizeof(mstring));
 
         if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
             perror(ifr.ifr_name);
@@ -99,16 +103,6 @@
         } else
             flags = ifr.ifr_flags;
 
-        sprintf(astring, "%d.%d.%d.%d",
-                addr & 0xff,
-                ((addr >> 8) & 0xff),
-                ((addr >> 16) & 0xff),
-                ((addr >> 24) & 0xff));
-        sprintf(mstring, "%d.%d.%d.%d",
-                mask & 0xff,
-                ((mask >> 8) & 0xff),
-                ((mask >> 16) & 0xff),
-                ((mask >> 24) & 0xff));
         printf("%s: ip %s mask %s flags [", ifr.ifr_name,
                astring,
                mstring
diff --git a/toolbox/insmod.c b/toolbox/insmod.c
index fb1448b..d252433 100644
--- a/toolbox/insmod.c
+++ b/toolbox/insmod.c
@@ -73,7 +73,7 @@
 		char *ptr = opts;
 
 		for (i = 2; (i < argc) && (ptr < end); i++) {
-			len = MIN(strlen(argv[i]), end - ptr);
+			len = MIN(strlen(argv[i]), (size_t)(end - ptr));
 			memcpy(ptr, argv[i], len);
 			ptr += len;
 			*ptr++ = ' ';
diff --git a/toolbox/ioctl.c b/toolbox/ioctl.c
index fb555d2..17fabff 100644
--- a/toolbox/ioctl.c
+++ b/toolbox/ioctl.c
@@ -21,9 +21,9 @@
     int arg_size = 4;
     int direct_arg = 0;
     uint32_t ioctl_nr;
-    void *ioctl_args;
+    void *ioctl_args = NULL;
     uint8_t *ioctl_argp;
-    uint8_t *ioctl_argp_save;
+    uint8_t *ioctl_argp_save = NULL;
     int rem;
 
     do {
@@ -112,6 +112,7 @@
     else
         res = ioctl(fd, ioctl_nr, 0);
     if (res < 0) {
+        free(ioctl_args);
         fprintf(stderr, "ioctl 0x%x failed, %d\n", ioctl_nr, res);
         return 1;
     }
@@ -124,5 +125,6 @@
         }
         printf("\n");
     }
+    free(ioctl_args);
     return 0;
 }
diff --git a/toolbox/load_policy.c b/toolbox/load_policy.c
index eb5aba6..90d48c4 100644
--- a/toolbox/load_policy.c
+++ b/toolbox/load_policy.c
@@ -10,7 +10,7 @@
 
 int load_policy_main(int argc, char **argv)
 {
-    int fd, rc, vers;
+    int fd, rc;
     struct stat sb;
     void *map;
     const char *path;
diff --git a/toolbox/ls.c b/toolbox/ls.c
index 3cc5bb2..011f7b5 100644
--- a/toolbox/ls.c
+++ b/toolbox/ls.c
@@ -137,7 +137,7 @@
 
     /* blocks are 512 bytes, we want output to be KB */
     if ((flags & LIST_SIZE) != 0) {
-        printf("%lld ", s->st_blocks / 2);
+        printf("%lld ", (long long)s->st_blocks / 2);
     }
 
     if ((flags & LIST_CLASSIFY) != 0) {
@@ -205,7 +205,7 @@
         break;
     case S_IFREG:
         printf("%s %-8s %-8s %8lld %s %s\n",
-               mode, user, group, s->st_size, date, name);
+               mode, user, group, (long long)s->st_size, date, name);
         break;
     case S_IFLNK: {
         char linkto[256];
@@ -321,7 +321,7 @@
     }
 
     if(flags & LIST_INODE) {
-        printf("%8llu ", s.st_ino);
+        printf("%8llu ", (unsigned long long)s.st_ino);
     }
 
     if ((flags & LIST_MACLABEL) != 0) {
@@ -443,7 +443,6 @@
 int ls_main(int argc, char **argv)
 {
     int flags = 0;
-    int listed = 0;
 
     if(argc > 1) {
         int i;
diff --git a/toolbox/lsof.c b/toolbox/lsof.c
index 113c120..bee981d 100644
--- a/toolbox/lsof.c
+++ b/toolbox/lsof.c
@@ -99,10 +99,7 @@
 static void print_maps(struct pid_info_t* info)
 {
     FILE *maps;
-    char buffer[PATH_MAX + 100];
-
     size_t offset;
-    int major, minor;
     char device[10];
     long int inode;
     char file[PATH_MAX];
@@ -113,7 +110,7 @@
     if (!maps)
         goto out;
 
-    while (fscanf(maps, "%*x-%*x %*s %zx %5s %ld %s\n", &offset, device, &inode,
+    while (fscanf(maps, "%*x-%*x %*s %zx %s %ld %s\n", &offset, device, &inode,
             file) == 4) {
         // We don't care about non-file maps
         if (inode == 0 || !strcmp(device, "00:00"))
diff --git a/toolbox/md5.c b/toolbox/md5.c
index 2fb8b05..5de4d9e 100644
--- a/toolbox/md5.c
+++ b/toolbox/md5.c
@@ -4,12 +4,7 @@
 #include <unistd.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <md5.h>
-
-/* When this was written, bionic's md5.h did not define this. */
-#ifndef MD5_DIGEST_LENGTH
-#define MD5_DIGEST_LENGTH 16
-#endif
+#include <openssl/md5.h>
 
 static int usage()
 {
@@ -30,7 +25,6 @@
         return -1;
     }
 
-    /* Note that bionic's MD5_* functions return void. */
     MD5_Init(&md5_ctx);
 
     while (1) {
diff --git a/toolbox/mkdir.c b/toolbox/mkdir.c
index 656970a..398d350 100644
--- a/toolbox/mkdir.c
+++ b/toolbox/mkdir.c
@@ -15,7 +15,6 @@
 
 int mkdir_main(int argc, char *argv[])
 {
-    int symbolic = 0;
     int ret;
     if(argc < 2 || strcmp(argv[1], "--help") == 0) {
         return usage();
diff --git a/toolbox/mknod.c b/toolbox/mknod.c
new file mode 100644
index 0000000..0fedece
--- /dev/null
+++ b/toolbox/mknod.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2014, 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>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+static int print_usage() {
+    fprintf(stderr, "mknod <path> [b|c|u|p] <major> <minor>\n");
+    return EXIT_FAILURE;
+}
+
+int mknod_main(int argc, char **argv) {
+    char *path = NULL;
+    int major = 0;
+    int minor = 0;
+    int args = 0;
+    mode_t mode = 0660;
+
+    /* Check correct argument count is 3 or 5 */
+    if (argc != 3 && argc != 5) {
+        fprintf(stderr, "Incorrect argument count\n");
+        return print_usage();
+    }
+
+    path = argv[1];
+
+    const char node_type = *argv[2];
+    switch (node_type) {
+    case 'b':
+        mode |= S_IFBLK;
+        args = 5;
+        break;
+    case 'c':
+    case 'u':
+        mode |= S_IFCHR;
+        args = 5;
+        break;
+    case 'p':
+        mode |= S_IFIFO;
+        args = 3;
+        break;
+    default:
+        fprintf(stderr, "Invalid node type '%c'\n", node_type);
+        return print_usage();
+    }
+
+    if (argc != args) {
+        if (args == 5) {
+            fprintf(stderr, "Node type '%c' requires <major> and <minor>\n", node_type);
+        } else {
+            fprintf(stderr, "Node type '%c' does not require <major> and <minor>\n", node_type);
+        }
+        return print_usage();
+    }
+
+    if (args == 5) {
+        major = atoi(argv[3]);
+        minor = atoi(argv[4]);
+    }
+
+    if (mknod(path, mode, makedev(major, minor))) {
+        perror("Unable to create node");
+        return EXIT_FAILURE;
+    }
+    return 0;
+}
diff --git a/toolbox/mkswap.c b/toolbox/mkswap.c
index 1710ef6..0904152 100644
--- a/toolbox/mkswap.c
+++ b/toolbox/mkswap.c
@@ -1,6 +1,5 @@
 #include <stdio.h>
 #include <unistd.h>
-#include <asm/page.h>
 #include <sys/swap.h>
 #include <sys/types.h>
 #include <sys/stat.h>
diff --git a/toolbox/nandread.c b/toolbox/nandread.c
index d43b2fe..bd19942 100644
--- a/toolbox/nandread.c
+++ b/toolbox/nandread.c
@@ -1,9 +1,10 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
 #include <mtd/mtd-user.h>
@@ -177,11 +178,7 @@
 
     if (rawmode) {
         rawmode = mtdinfo.oobsize;
-#if !defined(MTD_STUPID_LOCK) /* using uapi kernel headers */
         ret = ioctl(fd, MTDFILEMODE, MTD_FILE_MODE_RAW);
-#else /* still using old kernel headers */
-        ret = ioctl(fd, MTDFILEMODE, MTD_MODE_RAW);
-#endif
         if (ret) {
             fprintf(stderr, "failed set raw mode for %s, %s\n",
                     devname, strerror(errno));
@@ -193,18 +190,18 @@
     for (pos = start, opos = 0; pos < end; pos += mtdinfo.writesize) {
         bad_block = 0;
         if (verbose > 3)
-            printf("reading at %llx\n", pos);
+            printf("reading at %" PRIx64 "\n", pos);
         lseek64(fd, pos, SEEK_SET);
         ret = read(fd, buffer, mtdinfo.writesize + rawmode);
         if (ret < (int)mtdinfo.writesize) {
-            fprintf(stderr, "short read at %llx, %d\n", pos, ret);
+            fprintf(stderr, "short read at %" PRIx64 ", %d\n", pos, ret);
             bad_block = 2;
         }
         if (!rawmode) {
             oobbuf.start = pos;
             ret = ioctl(fd, MEMREADOOB, &oobbuf);
             if (ret) {
-                fprintf(stderr, "failed to read oob data at %llx, %d\n", pos, ret);
+                fprintf(stderr, "failed to read oob data at %" PRIx64 ", %d\n", pos, ret);
                 bad_block = 2;
             }
         }
@@ -217,17 +214,17 @@
         bpos = pos / mtdinfo.erasesize * mtdinfo.erasesize;
         ret = ioctl(fd, MEMGETBADBLOCK, &bpos);
         if (ret && errno != EOPNOTSUPP) {
-            printf("badblock at %llx\n", pos);
+            printf("badblock at %" PRIx64 "\n", pos);
             bad_block = 1;
         }
         if (ecc.corrected != last_ecc.corrected)
-            printf("ecc corrected, %u, at %llx\n", ecc.corrected - last_ecc.corrected, pos);
+            printf("ecc corrected, %u, at %" PRIx64 "\n", ecc.corrected - last_ecc.corrected, pos);
         if (ecc.failed != last_ecc.failed)
-            printf("ecc failed, %u, at %llx\n", ecc.failed - last_ecc.failed, pos);
+            printf("ecc failed, %u, at %" PRIx64 "\n", ecc.failed - last_ecc.failed, pos);
         if (ecc.badblocks != last_ecc.badblocks)
-            printf("ecc badblocks, %u, at %llx\n", ecc.badblocks - last_ecc.badblocks, pos);
+            printf("ecc badblocks, %u, at %" PRIx64 "\n", ecc.badblocks - last_ecc.badblocks, pos);
         if (ecc.bbtblocks != last_ecc.bbtblocks)
-            printf("ecc bbtblocks, %u, at %llx\n", ecc.bbtblocks - last_ecc.bbtblocks, pos);
+            printf("ecc bbtblocks, %u, at %" PRIx64 "\n", ecc.bbtblocks - last_ecc.bbtblocks, pos);
 
         if (!rawmode) {
             oob_fixed = (uint8_t *)oob_data;
@@ -245,18 +242,18 @@
         if (outfd >= 0) {
             ret = write(outfd, buffer, mtdinfo.writesize + spare_size);
             if (ret < (int)(mtdinfo.writesize + spare_size)) {
-                fprintf(stderr, "short write at %llx, %d\n", pos, ret);
+                fprintf(stderr, "short write at %" PRIx64 ", %d\n", pos, ret);
                 close(outfd);
                 outfd = -1;
             }
             if (ecc.corrected != last_ecc.corrected)
-                fprintf(statusfile, "%08llx: ecc corrected\n", opos);
+                fprintf(statusfile, "%08" PRIx64 ": ecc corrected\n", opos);
             if (ecc.failed != last_ecc.failed)
-                fprintf(statusfile, "%08llx: ecc failed\n", opos);
+                fprintf(statusfile, "%08" PRIx64 ": ecc failed\n", opos);
             if (bad_block == 1)
-                fprintf(statusfile, "%08llx: badblock\n", opos);
+                fprintf(statusfile, "%08" PRIx64 ": badblock\n", opos);
             if (bad_block == 2)
-                fprintf(statusfile, "%08llx: read error\n", opos);
+                fprintf(statusfile, "%08" PRIx64 ": read error\n", opos);
             opos += mtdinfo.writesize + spare_size;
         }
 
@@ -265,7 +262,7 @@
         if (test_empty(buffer, mtdinfo.writesize + mtdinfo.oobsize + spare_size))
             empty_pages++;
         else if (verbose > 2 || (verbose > 1 && !(pos & (mtdinfo.erasesize - 1))))
-            printf("page at %llx (%d oobbytes): %08x %08x %08x %08x "
+            printf("page at %" PRIx64 " (%d oobbytes): %08x %08x %08x %08x "
                    "%08x %08x %08x %08x\n", pos, oobbuf.start,
                    oob_data[0], oob_data[1], oob_data[2], oob_data[3],
                    oob_data[4], oob_data[5], oob_data[6], oob_data[7]);
diff --git a/toolbox/newfs_msdos.c b/toolbox/newfs_msdos.c
index 27dca42..30b9f77 100644
--- a/toolbox/newfs_msdos.c
+++ b/toolbox/newfs_msdos.c
@@ -360,7 +360,7 @@
     if (!opt_create && !strchr(fname, '/')) {
 	snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname);
 	if (!(fname = strdup(buf)))
-	    err(1, NULL);
+	    err(1, "%s", buf);
     }
     dtype = *argv;
     if (opt_create) {
@@ -493,7 +493,7 @@
 	if (!strchr(bname, '/')) {
 	    snprintf(buf, sizeof(buf), "/boot/%s", bname);
 	    if (!(bname = strdup(buf)))
-		err(1, NULL);
+		err(1, "%s", buf);
 	}
 	if ((fd1 = open(bname, O_RDONLY)) == -1 || fstat(fd1, &sb))
 	    err(1, "%s", bname);
@@ -611,7 +611,7 @@
 	now = tv.tv_sec;
 	tm = localtime(&now);
 	if (!(img = malloc(bpb.bps)))
-	    err(1, NULL);
+	    err(1, "%u", bpb.bps);
 	dir = bpb.res + (bpb.spf ? bpb.spf : bpb.bspf) * bpb.nft;
 	for (lsn = 0; lsn < dir + (fat == 32 ? bpb.spc : rds); lsn++) {
 	    x = lsn;
@@ -728,14 +728,14 @@
 static void
 check_mounted(const char *fname, mode_t mode)
 {
+#ifdef ANDROID
+    warnx("Skipping mount checks");
+#else
     struct statfs *mp;
     const char *s1, *s2;
     size_t len;
     int n, r;
 
-#ifdef ANDROID
-    warnx("Skipping mount checks");
-#else
     if (!(n = getmntinfo(&mp, MNT_NOWAIT)))
 	err(1, "getmntinfo");
     len = strlen(_PATH_DEV);
diff --git a/toolbox/nohup.c b/toolbox/nohup.c
new file mode 100644
index 0000000..363999d
--- /dev/null
+++ b/toolbox/nohup.c
@@ -0,0 +1,26 @@
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int nohup_main(int argc, char *argv[])
+{
+    if (argc < 2) {
+        fprintf(stderr, "Usage: %s [-n] program args...\n", argv[0]);
+        return EXIT_FAILURE;
+    }
+    signal(SIGHUP, SIG_IGN);
+    argv++;
+    if (strcmp(argv[0], "-n") == 0) {
+        argv++;
+        signal(SIGINT, SIG_IGN);
+        signal(SIGSTOP, SIG_IGN);
+        signal(SIGTTIN, SIG_IGN);
+        signal(SIGTTOU, SIG_IGN);
+        signal(SIGQUIT, SIG_IGN);
+        signal(SIGTERM, SIG_IGN);
+    }
+    execvp(argv[0], argv);
+    perror(argv[0]);
+    return EXIT_FAILURE;
+}
diff --git a/toolbox/ps.c b/toolbox/ps.c
index 7c35ccb..57b4280 100644
--- a/toolbox/ps.c
+++ b/toolbox/ps.c
@@ -28,9 +28,12 @@
 #define SHOW_POLICY 4
 #define SHOW_CPU  8
 #define SHOW_MACLABEL 16
+#define SHOW_ABI 32
 
 static int display_flags = 0;
 
+static void print_exe_abi(int pid);
+
 static int ps_line(int pid, int tid, char *namefilter)
 {
     char statline[1024];
@@ -40,7 +43,7 @@
     struct stat stats;
     int fd, r;
     char *ptr, *name, *state;
-    int ppid, tty;
+    int ppid;
     unsigned wchan, rss, vss, eip;
     unsigned utime, stime;
     int prio, nice, rtprio, sched, psr;
@@ -88,7 +91,7 @@
     ppid = atoi(nexttok(&ptr));
     nexttok(&ptr); // pgrp
     nexttok(&ptr); // sid
-    tty = atoi(nexttok(&ptr));
+    nexttok(&ptr); // tty
     
     nexttok(&ptr); // tpgid
     nexttok(&ptr); // flags
@@ -130,7 +133,7 @@
     rtprio = atoi(nexttok(&ptr)); // rt_priority
     sched = atoi(nexttok(&ptr)); // scheduling policy
     
-    tty = atoi(nexttok(&ptr));
+    nexttok(&ptr); // tty
     
     if(tid != 0) {
         ppid = pid;
@@ -170,7 +173,11 @@
             else
                 printf(" %.2s ", get_sched_policy_name(p));
         }
-        printf(" %08x %08x %s %s", wchan, eip, state, cmdline[0] ? cmdline : name);
+        printf(" %08x %08x %s ", wchan, eip, state);
+        if (display_flags & SHOW_ABI) {
+            print_exe_abi(pid);
+        }
+        printf("%s", cmdline[0] ? cmdline : name);
         if(display_flags&SHOW_TIME)
             printf(" (u:%d, s:%d)", utime, stime);
 
@@ -179,6 +186,39 @@
     return 0;
 }
 
+static void print_exe_abi(int pid)
+{
+    int fd, r;
+    char exeline[1024];
+
+    sprintf(exeline, "/proc/%d/exe", pid);
+    fd = open(exeline, O_RDONLY);
+    if(fd == 0) {
+        printf("    ");
+        return;
+    }
+    r = read(fd, exeline, 5 /* 4 byte ELFMAG + 1 byte EI_CLASS */);
+    close(fd);
+    if(r < 0) {
+        printf("    ");
+        return;
+    }
+    if (memcmp("\177ELF", exeline, 4) != 0) {
+        printf("??  ");
+        return;
+    }
+    switch (exeline[4]) {
+        case 1:
+            printf("32  ");
+            return;
+        case 2:
+            printf("64  ");
+            return;
+        default:
+            printf("??  ");
+            return;
+    }
+}
 
 void ps_threads(int pid, char *namefilter)
 {
@@ -224,7 +264,9 @@
             display_flags |= SHOW_PRIO;
         } else if(!strcmp(argv[1],"-c")) {
             display_flags |= SHOW_CPU;
-        }  else if(isdigit(argv[1][0])){
+        } else if(!strcmp(argv[1],"--abi")) {
+            display_flags |= SHOW_ABI;
+        } else if(isdigit(argv[1][0])){
             pidfilter = atoi(argv[1]);
         } else {
             namefilter = argv[1];
@@ -236,10 +278,11 @@
     if (display_flags & SHOW_MACLABEL) {
         printf("LABEL                          USER     PID   PPID  NAME\n");
     } else {
-        printf("USER     PID   PPID  VSIZE  RSS   %s%s %s WCHAN    PC         NAME\n",
+        printf("USER     PID   PPID  VSIZE  RSS   %s%s %s WCHAN    PC        %sNAME\n",
                (display_flags&SHOW_CPU)?"CPU ":"",
                (display_flags&SHOW_PRIO)?"PRIO  NICE  RTPRI SCHED ":"",
-               (display_flags&SHOW_POLICY)?"PCY " : "");
+               (display_flags&SHOW_POLICY)?"PCY " : "",
+               (display_flags&SHOW_ABI)?"ABI " : "");
     }
     while((de = readdir(d)) != 0){
         if(isdigit(de->d_name[0])){
diff --git a/toolbox/restorecon.c b/toolbox/restorecon.c
index f9f604f..3568625 100644
--- a/toolbox/restorecon.c
+++ b/toolbox/restorecon.c
@@ -2,76 +2,44 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fts.h>
 #include <selinux/selinux.h>
-#include <selinux/label.h>
 #include <selinux/android.h>
 
-static struct selabel_handle *sehandle;
 static const char *progname;
-static int nochange;
-static int verbose;
 
 static void usage(void)
 {
-    fprintf(stderr, "usage:  %s [-nrRv] pathname...\n", progname);
+    fprintf(stderr, "usage:  %s [-DFnrRv] pathname...\n", progname);
     exit(1);
 }
 
-static int restore(const char *pathname, const struct stat *sb)
-{
-    char *oldcontext, *newcontext;
-
-    if (lgetfilecon(pathname, &oldcontext) < 0) {
-        fprintf(stderr, "Could not get context of %s:  %s\n",
-                pathname, strerror(errno));
-        return -1;
-    }
-    if (selabel_lookup(sehandle, &newcontext, pathname, sb->st_mode) < 0) {
-        fprintf(stderr, "Could not lookup context for %s:  %s\n", pathname,
-                strerror(errno));
-        return -1;
-    }
-    if (strcmp(newcontext, "<<none>>") &&
-        strcmp(oldcontext, newcontext)) {
-        if (verbose)
-            printf("Relabeling %s from %s to %s.\n", pathname, oldcontext, newcontext);
-        if (!nochange) {
-            if (lsetfilecon(pathname, newcontext) < 0) {
-                fprintf(stderr, "Could not label %s with %s:  %s\n",
-                        pathname, newcontext, strerror(errno));
-                return -1;
-            }
-        }
-    }
-    freecon(oldcontext);
-    freecon(newcontext);
-    return 0;
-}
-
 int restorecon_main(int argc, char **argv)
 {
-    int ch, recurse = 0, ftsflags = FTS_PHYSICAL;
-    int i = 0;
+    int ch, i, rc;
+    unsigned int flags = 0;
 
     progname = argv[0];
 
     do {
-        ch = getopt(argc, argv, "nrRv");
+        ch = getopt(argc, argv, "DFnrRv");
         if (ch == EOF)
             break;
         switch (ch) {
+        case 'D':
+            flags |= SELINUX_ANDROID_RESTORECON_DATADATA;
+            break;
+        case 'F':
+            flags |= SELINUX_ANDROID_RESTORECON_FORCE;
+            break;
         case 'n':
-            nochange = 1;
+            flags |= SELINUX_ANDROID_RESTORECON_NOCHANGE;
             break;
         case 'r':
         case 'R':
-            recurse = 1;
+            flags |= SELINUX_ANDROID_RESTORECON_RECURSE;
             break;
         case 'v':
-            verbose = 1;
+            flags |= SELINUX_ANDROID_RESTORECON_VERBOSE;
             break;
         default:
             usage();
@@ -83,53 +51,11 @@
     if (!argc)
         usage();
 
-    sehandle = selinux_android_file_context_handle();
-
-    if (!sehandle) {
-        fprintf(stderr, "Could not load file_contexts:  %s\n",
-                strerror(errno));
-        return -1;
-    }
-
-    if (recurse) {
-        FTS *fts;
-        FTSENT *ftsent;
-        fts = fts_open(argv, ftsflags, NULL);
-        if (!fts) {
-            fprintf(stderr, "Could not traverse filesystems (first was %s):  %s\n",
-                    argv[0], strerror(errno));
-            return -1;
-        }
-        while ((ftsent = fts_read(fts))) {
-            switch (ftsent->fts_info) {
-            case FTS_DP:
-                break;
-            case FTS_DNR:
-            case FTS_ERR:
-            case FTS_NS:
-                fprintf(stderr, "Could not access %s:  %s\n", ftsent->fts_path,
-                        strerror(errno));
-                fts_set(fts, ftsent, FTS_SKIP);
-                break;
-            default:
-                if (restore(ftsent->fts_path, ftsent->fts_statp) < 0)
-                    fts_set(fts, ftsent, FTS_SKIP);
-                break;
-            }
-        }
-    } else {
-        int i, rc;
-        struct stat sb;
-
-        for (i = 0; i < argc; i++) {
-            rc = lstat(argv[i], &sb);
-            if (rc < 0) {
-                fprintf(stderr, "Could not stat %s:  %s\n", argv[i],
-                        strerror(errno));
-                continue;
-            }
-            restore(argv[i], &sb);
-        }
+    for (i = 0; i < argc; i++) {
+        rc = selinux_android_restorecon(argv[i], flags);
+        if (rc < 0)
+            fprintf(stderr, "Could not restorecon %s:  %s\n", argv[i],
+                    strerror(errno));
     }
 
     return 0;
diff --git a/toolbox/rmdir.c b/toolbox/rmdir.c
index 06f3df2..749fec8 100644
--- a/toolbox/rmdir.c
+++ b/toolbox/rmdir.c
@@ -11,7 +11,6 @@
 
 int rmdir_main(int argc, char *argv[])
 {
-    int symbolic = 0;
     int ret;
     if(argc < 2) return usage();
 
diff --git a/toolbox/schedtop.c b/toolbox/schedtop.c
index a76f968..2fccd2e 100644
--- a/toolbox/schedtop.c
+++ b/toolbox/schedtop.c
@@ -1,26 +1,23 @@
-#include <stdio.h>
-#include <stdlib.h>
 #include <ctype.h>
+#include <dirent.h>
 #include <fcntl.h>
-#include <unistd.h>
-
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
 #include <stdint.h>
+#include <stdlib.h>
 #include <string.h>
-
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <dirent.h>
-#include <signal.h>
-
-#include <pwd.h>
+#include <unistd.h>
 
 struct thread_info {
     int pid;
     int tid;
     char name[64];
-    uint64_t exec_time;
-    uint64_t delay_time;
-    uint32_t run_count;
+    unsigned long long exec_time;
+    unsigned long long delay_time;
+    unsigned long long run_count;
 };
 
 struct thread_table {
@@ -110,7 +107,8 @@
         sprintf(line, "/proc/%d/schedstat", pid);
     if (read_line(line, sizeof(line)))
         return;
-    if(sscanf(line, "%llu %llu %u", &info->exec_time, &info->delay_time, &info->run_count) != 3)
+    if(sscanf(line, "%llu %llu %llu",
+              &info->exec_time, &info->delay_time, &info->run_count) != 3)
         return;
     if (proc_info) {
         proc_info->exec_time += info->exec_time;
@@ -183,7 +181,7 @@
         if (j == threads.active)
             printf(" %5u died\n", tid);
         else if (!(flags & FLAG_HIDE_IDLE) || threads.data[j].run_count - last_threads.data[i].run_count)
-            printf(" %5u %2u.%0*u %2u.%0*u %5u %5u.%0*u %5u.%0*u %7u  %s\n", tid,
+            printf(" %5u %2u.%0*u %2u.%0*u %5llu %5u.%0*u %5u.%0*u %7llu  %s\n", tid,
                 NS_TO_S_D(threads.data[j].exec_time - last_threads.data[i].exec_time),
                 NS_TO_S_D(threads.data[j].delay_time - last_threads.data[i].delay_time),
                 threads.data[j].run_count - last_threads.data[i].run_count,
@@ -229,14 +227,13 @@
     }
     for (i = 0; i < last_processes.active; i++) {
         int pid = last_processes.data[i].pid;
-        int tid = last_processes.data[i].tid;
         for (j = 0; j < processes.active; j++)
             if (pid == processes.data[j].pid)
                 break;
         if (j == processes.active)
             printf("%5u died\n", pid);
         else if (!(flags & FLAG_HIDE_IDLE) || processes.data[j].run_count - last_processes.data[i].run_count) {
-            printf("%5u  %2u.%0*u %2u.%0*u %5u %5u.%0*u %5u.%0*u %7u %s\n", pid,
+            printf("%5u  %2u.%0*u %2u.%0*u %5llu %5u.%0*u %5u.%0*u %7llu %s\n", pid,
                 NS_TO_S_D(processes.data[j].exec_time - last_processes.data[i].exec_time),
                 NS_TO_S_D(processes.data[j].delay_time - last_processes.data[i].delay_time),
                 processes.data[j].run_count - last_processes.data[i].run_count,
@@ -272,9 +269,6 @@
 {
     int c;
     DIR *d;
-    struct dirent *de;
-    char *namefilter = 0;
-    int pidfilter = 0;
     uint32_t flags = 0;    
     int delay = 3000000;
     float delay_f;
diff --git a/toolbox/sendevent.c b/toolbox/sendevent.c
index 1608e6c..9b813f6 100644
--- a/toolbox/sendevent.c
+++ b/toolbox/sendevent.c
@@ -47,9 +47,8 @@
 
 int sendevent_main(int argc, char *argv[])
 {
-    int i;
     int fd;
-    int ret;
+    ssize_t ret;
     int version;
     struct input_event event;
 
@@ -72,7 +71,7 @@
     event.code = atoi(argv[3]);
     event.value = atoi(argv[4]);
     ret = write(fd, &event, sizeof(event));
-    if(ret < sizeof(event)) {
+    if(ret < (ssize_t) sizeof(event)) {
         fprintf(stderr, "write event failed, %s\n", strerror(errno));
         return -1;
     }
diff --git a/toolbox/start.c b/toolbox/start.c
index 665a941..0941e64 100644
--- a/toolbox/start.c
+++ b/toolbox/start.c
@@ -7,14 +7,13 @@
 
 int start_main(int argc, char *argv[])
 {
-    char buf[1024];
-
     if(argc > 1) {
         property_set("ctl.start", argv[1]);
     } else {
         /* defaults to starting the common services stopped by stop.c */
         property_set("ctl.start", "surfaceflinger");
         property_set("ctl.start", "zygote");
+        property_set("ctl.start", "zygote_secondary");
     }
 
     return 0;
diff --git a/toolbox/stop.c b/toolbox/stop.c
index 460f377..ed9a293 100644
--- a/toolbox/stop.c
+++ b/toolbox/stop.c
@@ -5,12 +5,11 @@
 
 int stop_main(int argc, char *argv[])
 {
-    char buf[1024];
-
     if(argc > 1) {
         property_set("ctl.stop", argv[1]);
     } else{
         /* defaults to stopping the common services */
+        property_set("ctl.stop", "zygote_secondary");
         property_set("ctl.stop", "zygote");
         property_set("ctl.stop", "surfaceflinger");
     }
diff --git a/toolbox/swapoff.c b/toolbox/swapoff.c
index 8f14158..d8f6a00 100644
--- a/toolbox/swapoff.c
+++ b/toolbox/swapoff.c
@@ -1,6 +1,5 @@
 #include <stdio.h>
 #include <unistd.h>
-#include <asm/page.h>
 #include <sys/swap.h>
 
 int swapoff_main(int argc, char **argv)
diff --git a/toolbox/swapon.c b/toolbox/swapon.c
index a810b3d..21d2287 100644
--- a/toolbox/swapon.c
+++ b/toolbox/swapon.c
@@ -2,7 +2,6 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <getopt.h>
-#include <asm/page.h>
 #include <sys/swap.h>
 
 void usage(char *name)
diff --git a/toolbox/syren.c b/toolbox/syren.c
index 06e329e..47c2460 100644
--- a/toolbox/syren.c
+++ b/toolbox/syren.c
@@ -123,7 +123,11 @@
 
 	r = find_reg(argv[2]);
 	if (r == NULL) {
-		strcpy(name, argv[2]);
+		if(strlen(argv[2]) >= sizeof(name)){
+			fprintf(stderr, "REGNAME too long\n");
+			return 0;
+		}
+		strlcpy(name, argv[2], sizeof(name));
 		char *addr_str = strchr(argv[2], ':');
 		if (addr_str == NULL)
 			return usage();
@@ -131,7 +135,7 @@
 		sio.page = strtoul(argv[2], 0, 0);
 		sio.addr = strtoul(addr_str, 0, 0);
 	} else {
-		strcpy(name, r->name);
+		strlcpy(name, r->name, sizeof(name));
 		sio.page = r->page;
 		sio.addr = r->addr;
 	}
diff --git a/toolbox/top.c b/toolbox/top.c
index 7642522..280a032 100644
--- a/toolbox/top.c
+++ b/toolbox/top.c
@@ -9,7 +9,7 @@
  *    notice, this list of conditions and the following disclaimer.
  *  * Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the 
+ *    the documentation and/or other materials provided with the
  *    distribution.
  *  * Neither the name of Google, Inc. nor the names of its contributors
  *    may be used to endorse or promote products derived from this
@@ -22,7 +22,7 @@
  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
@@ -108,16 +108,20 @@
 static int numcmp(long long a, long long b);
 static void usage(char *cmd);
 
-int top_main(int argc, char *argv[]) {
-    int i;
+static void exit_top(int signal) {
+  exit(EXIT_FAILURE);
+}
 
+int top_main(int argc, char *argv[]) {
     num_used_procs = num_free_procs = 0;
 
+    signal(SIGPIPE, exit_top);
+
     max_procs = 0;
     delay = 3;
     iterations = -1;
     proc_cmp = &proc_cpu_cmp;
-    for (i = 1; i < argc; i++) {
+    for (int i = 1; i < argc; i++) {
         if (!strcmp(argv[i], "-m")) {
             if (i + 1 >= argc) {
                 fprintf(stderr, "Option -m expects an argument.\n");
@@ -249,9 +253,9 @@
             continue;
 
         pid = atoi(pid_dir->d_name);
-        
+
         struct proc_info cur_proc;
-        
+
         if (!threads) {
             proc = alloc_proc();
 
@@ -275,7 +279,7 @@
 
             sprintf(filename, "/proc/%d/status", pid);
             read_status(filename, &cur_proc);
-            
+
             proc = NULL;
         }
 
@@ -310,7 +314,7 @@
         }
 
         closedir(task_dir);
-        
+
         if (!threads)
             add_proc(proc_num++, proc);
     }
@@ -324,7 +328,6 @@
 static int read_stat(char *filename, struct proc_info *proc) {
     FILE *file;
     char buf[MAX_LINE], *open_paren, *close_paren;
-    int res, idx;
 
     file = fopen(filename, "r");
     if (!file) return 1;
@@ -339,7 +342,7 @@
     *open_paren = *close_paren = '\0';
     strncpy(proc->tname, open_paren + 1, THREAD_NAME_LEN);
     proc->tname[THREAD_NAME_LEN-1] = 0;
-    
+
     /* Scan rest of string. */
     sscanf(close_paren + 1, " %c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
                  "%lu %lu %*d %*d %*d %*d %*d %*d %*d %lu %ld "
@@ -410,9 +413,7 @@
     struct proc_info *old_proc, *proc;
     long unsigned total_delta_time;
     struct passwd *user;
-    struct group *group;
     char *user_str, user_buf[20];
-    char *group_str, group_buf[20];
 
     for (i = 0; i < num_new_procs; i++) {
         if (new_procs[i]) {
@@ -452,7 +453,7 @@
             new_cpu.sirqtime - old_cpu.sirqtime,
             total_delta_time);
     printf("\n");
-    if (!threads) 
+    if (!threads)
         printf("%5s %2s %4s %1s %5s %7s %7s %3s %-8s %s\n", "PID", "PR", "CPU%", "S", "#THR", "VSS", "RSS", "PCY", "UID", "Name");
     else
         printf("%5s %5s %2s %4s %1s %7s %7s %3s %-8s %-15s %s\n", "PID", "TID", "PR", "CPU%", "S", "VSS", "RSS", "PCY", "UID", "Thread", "Proc");
@@ -463,20 +464,13 @@
         if (!proc || (max_procs && (i >= max_procs)))
             break;
         user  = getpwuid(proc->uid);
-        group = getgrgid(proc->gid);
         if (user && user->pw_name) {
             user_str = user->pw_name;
         } else {
             snprintf(user_buf, 20, "%d", proc->uid);
             user_str = user_buf;
         }
-        if (group && group->gr_name) {
-            group_str = group->gr_name;
-        } else {
-            snprintf(group_buf, 20, "%d", proc->gid);
-            group_str = group_buf;
-        }
-        if (!threads) 
+        if (!threads)
             printf("%5d %2d %3ld%% %c %5d %6ldK %6ldK %3s %-8.8s %s\n", proc->pid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads,
                 proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->name[0] != 0 ? proc->name : proc->tname);
         else
diff --git a/toolbox/uid_from_user.c b/toolbox/uid_from_user.c
new file mode 100644
index 0000000..fd48d3c
--- /dev/null
+++ b/toolbox/uid_from_user.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014, 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.
+ *
+ * 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 <pwd.h>
+#include <sys/types.h>
+
+int uid_from_user(const char* name, uid_t* uid) {
+  struct passwd* pw = getpwnam(name);
+  if (pw == NULL) {
+    return -1;
+  }
+  *uid = pw->pw_uid;
+  return 0;
+}
diff --git a/toolbox/umount.c b/toolbox/umount.c
index 890e870..3e17396 100644
--- a/toolbox/umount.c
+++ b/toolbox/umount.c
@@ -33,7 +33,6 @@
     char mount_path[256];
     char rest[256];
     int result = 0;
-    int path_length = strlen(path);
     
     f = fopen("/proc/mounts", "r");
     if (!f) {
diff --git a/toolbox/watchprops.c b/toolbox/watchprops.c
index bf82882..0d05aba 100644
--- a/toolbox/watchprops.c
+++ b/toolbox/watchprops.c
@@ -6,8 +6,6 @@
 #include <cutils/properties.h>
 #include <cutils/hashmap.h>
 
-#include <sys/atomics.h>
-
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
 #include <sys/_system_properties.h>
 
@@ -23,9 +21,9 @@
 
 static void announce(char *name, char *value)
 {
-    char *x;
+    unsigned char *x;
     
-    for(x = value; *x; x++) {
+    for(x = (unsigned char *)value; *x; x++) {
         if((*x < 32) || (*x > 127)) *x = '.';
     }
 
@@ -77,9 +75,7 @@
 
 int watchprops_main(int argc, char *argv[])
 {
-    unsigned serial = 0;
-    unsigned count = 0;
-    unsigned n;
+    unsigned serial;
     
     Hashmap *watchlist = hashmapCreate(1024, str_hash, str_equals);
     if (!watchlist)
@@ -87,7 +83,7 @@
 
     __system_property_foreach(populate_watchlist, watchlist);
 
-    for(;;) {
+    for(serial = 0;;) {
         serial = __system_property_wait_any(serial);
         __system_property_foreach(update_watchlist, watchlist);
     }