am e3e22062: Merge "Add new cert_pin_failure tag that can be used in user-consent filtering." into klp-dev

* commit 'e3e22062f0a00bc23dade9c6f06d41e76dd7b351':
  Add new cert_pin_failure tag that can be used in user-consent filtering.
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index 68bb232..19b3022 100644
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -155,7 +155,10 @@
 #define VENDOR_ID_QISDA         0x1D45
 // ECS's USB Vendor ID
 #define VENDOR_ID_ECS           0x03fc
-
+// MSI's USB Vendor ID
+#define VENDOR_ID_MSI           0x0DB0
+// Wacom's USB Vendor ID
+#define VENDOR_ID_WACOM         0x0531
 
 /** built-in vendor list */
 int builtInVendorIds[] = {
@@ -219,6 +222,8 @@
     VENDOR_ID_NOOK,
     VENDOR_ID_QISDA,
     VENDOR_ID_ECS,
+    VENDOR_ID_MSI,
+    VENDOR_ID_WACOM,
 };
 
 #define BUILT_IN_VENDOR_COUNT    (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0]))
diff --git a/fastboot/usb_linux.c b/fastboot/usb_linux.c
index b7a9ca3..9153c8d 100644
--- a/fastboot/usb_linux.c
+++ b/fastboot/usb_linux.c
@@ -75,10 +75,18 @@
     unsigned char ep_out;
 };
 
+/* True if name isn't a valid name for a USB device in /sys/bus/usb/devices.
+ * Device names are made up of numbers, dots, and dashes, e.g., '7-1.5'.
+ * We reject interfaces (e.g., '7-1.5:1.0') and host controllers (e.g. 'usb1').
+ * The name must also start with a digit, to disallow '.' and '..'
+ */
 static inline int badname(const char *name)
 {
-    while(*name) {
-        if(!isdigit(*name++)) return 1;
+    if (!isdigit(*name))
+      return 1;
+    while(*++name) {
+        if(!isdigit(*name) && *name != '.' && *name != '-')
+            return 1;
     }
     return 0;
 }
@@ -95,7 +103,8 @@
     return 0;
 }
 
-static int filter_usb_device(int fd, char *ptr, int len, int writable,
+static int filter_usb_device(int fd, char* sysfs_name,
+                             char *ptr, int len, int writable,
                              ifc_match_func callback,
                              int *ept_in_id, int *ept_out_id, int *ifc_id)
 {
@@ -131,69 +140,35 @@
     info.dev_protocol = dev->bDeviceProtocol;
     info.writable = writable;
 
-    // read device serial number (if there is one)
-    info.serial_number[0] = 0;
-    if (dev->iSerialNumber) {
-        struct usbdevfs_ctrltransfer  ctrl;
-        // Keep it short enough because some bootloaders are borked if the URB len is > 255
-        // 128 is too big by 1.
-        __u16 buffer[127];
+    snprintf(info.device_path, sizeof(info.device_path), "usb:%s", sysfs_name);
 
-        memset(buffer, 0, sizeof(buffer));
-
-        ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
-        ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
-        ctrl.wValue = (USB_DT_STRING << 8) | dev->iSerialNumber;
-        //language ID (en-us) for serial number string
-        ctrl.wIndex = 0x0409;
-        ctrl.wLength = sizeof(buffer);
-        ctrl.data = buffer;
-        ctrl.timeout = 50;
-
-        result = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
-        if (result > 0) {
-            int i;
-            // skip first word, and copy the rest to the serial string, changing shorts to bytes.
-            result /= 2;
-            for (i = 1; i < result; i++)
-                info.serial_number[i - 1] = buffer[i];
-            info.serial_number[i - 1] = 0;
-        }
-    }
-
-    /* We need to get a path that represents a particular port on a particular
-     * hub.  We are passed an fd that was obtained by opening an entry under
-     * /dev/bus/usb.  Unfortunately, the names of those entries change each
-     * time devices are plugged and unplugged.  So how to get a repeatable
-     * path?  udevadm provided the inspiration.  We can get the major and
-     * minor of the device file, read the symlink that can be found here:
-     *   /sys/dev/char/<major>:<minor>
-     * and then use the last element of that path.  As a concrete example, I
-     * have an Android device at /dev/bus/usb/001/027 so working with bash:
-     *   $ ls -l /dev/bus/usb/001/027
-     *   crw-rw-r-- 1 root plugdev 189, 26 Apr  9 11:03 /dev/bus/usb/001/027
-     *   $ ls -l /sys/dev/char/189:26
-     *   lrwxrwxrwx 1 root root 0 Apr  9 11:03 /sys/dev/char/189:26 ->
-     *           ../../devices/pci0000:00/0000:00:1a.7/usb1/1-4/1-4.2/1-4.2.3
-     * So our device_path would be 1-4.2.3 which says my device is connected
-     * to port 3 of a hub on port 2 of a hub on port 4 of bus 1 (per
-     * http://www.linux-usb.org/FAQ.html).
+    /* Read device serial number (if there is one).
+     * We read the serial number from sysfs, since it's faster and more
+     * reliable than issuing a control pipe read, and also won't
+     * cause problems for devices which don't like getting descriptor
+     * requests while they're in the middle of flashing.
      */
-    info.device_path[0] = '\0';
-    result = fstat(fd, &st);
-    if (!result && S_ISCHR(st.st_mode)) {
-        char cdev[128];
-        char link[256];
-        char *slash;
-        ssize_t link_len;
-        snprintf(cdev, sizeof(cdev), "/sys/dev/char/%d:%d",
-                 major(st.st_rdev), minor(st.st_rdev));
-        link_len = readlink(cdev, link, sizeof(link) - 1);
-        if (link_len > 0) {
-            link[link_len] = '\0';
-            slash = strrchr(link, '/');
-            if (slash)
-                snprintf(info.device_path, sizeof(info.device_path), "usb:%s", slash+1);
+    info.serial_number[0] = '\0';
+    if (dev->iSerialNumber) {
+        char path[80];
+        int fd;
+
+        snprintf(path, sizeof(path),
+                 "/sys/bus/usb/devices/%s/serial", sysfs_name);
+        path[sizeof(path) - 1] = '\0';
+
+        fd = open(path, O_RDONLY);
+        if (fd >= 0) {
+            int chars_read = read(fd, info.serial_number,
+                                  sizeof(info.serial_number) - 1);
+            close(fd);
+
+            if (chars_read <= 0)
+                info.serial_number[0] = '\0';
+            else if (info.serial_number[chars_read - 1] == '\n') {
+                // strip trailing newline
+                info.serial_number[chars_read - 1] = '\0';
+            }
         }
     }
 
@@ -241,14 +216,73 @@
     return -1;
 }
 
+static int read_sysfs_string(const char *sysfs_name, const char *sysfs_node,
+                             char* buf, int bufsize)
+{
+    char path[80];
+    int fd, n;
+
+    snprintf(path, sizeof(path),
+             "/sys/bus/usb/devices/%s/%s", sysfs_name, sysfs_node);
+    path[sizeof(path) - 1] = '\0';
+
+    fd = open(path, O_RDONLY);
+    if (fd < 0)
+        return -1;
+
+    n = read(fd, buf, bufsize - 1);
+    close(fd);
+
+    if (n < 0)
+        return -1;
+
+    buf[n] = '\0';
+
+    return n;
+}
+
+static int read_sysfs_number(const char *sysfs_name, const char *sysfs_node)
+{
+    char buf[16];
+    int value;
+
+    if (read_sysfs_string(sysfs_name, sysfs_node, buf, sizeof(buf)) < 0)
+        return -1;
+
+    if (sscanf(buf, "%d", &value) != 1)
+        return -1;
+
+    return value;
+}
+
+/* Given the name of a USB device in sysfs, get the name for the same
+ * device in devfs. Returns 0 for success, -1 for failure.
+ */
+static int convert_to_devfs_name(const char* sysfs_name,
+                                 char* devname, int devname_size)
+{
+    int busnum, devnum;
+
+    busnum = read_sysfs_number(sysfs_name, "busnum");
+    if (busnum < 0)
+        return -1;
+
+    devnum = read_sysfs_number(sysfs_name, "devnum");
+    if (devnum < 0)
+        return -1;
+
+    snprintf(devname, devname_size, "/dev/bus/usb/%03d/%03d", busnum, devnum);
+    return 0;
+}
+
 static usb_handle *find_usb_device(const char *base, ifc_match_func callback)
 {
     usb_handle *usb = 0;
-    char busname[64], devname[64];
+    char devname[64];
     char desc[1024];
     int n, in, out, ifc;
 
-    DIR *busdir, *devdir;
+    DIR *busdir;
     struct dirent *de;
     int fd;
     int writable;
@@ -259,15 +293,7 @@
     while((de = readdir(busdir)) && (usb == 0)) {
         if(badname(de->d_name)) continue;
 
-        sprintf(busname, "%s/%s", base, de->d_name);
-        devdir = opendir(busname);
-        if(devdir == 0) continue;
-
-//        DBG("[ scanning %s ]\n", busname);
-        while((de = readdir(devdir)) && (usb == 0)) {
-
-            if(badname(de->d_name)) continue;
-            sprintf(devname, "%s/%s", busname, de->d_name);
+        if(!convert_to_devfs_name(de->d_name, devname, sizeof(devname))) {
 
 //            DBG("[ scanning %s ]\n", devname);
             writable = 1;
@@ -282,7 +308,7 @@
 
             n = read(fd, desc, sizeof(desc));
 
-            if(filter_usb_device(fd, desc, n, writable, callback,
+            if(filter_usb_device(fd, de->d_name, desc, n, writable, callback,
                                  &in, &out, &ifc) == 0) {
                 usb = calloc(1, sizeof(usb_handle));
                 strcpy(usb->fname, devname);
@@ -301,7 +327,6 @@
                 close(fd);
             }
         }
-        closedir(devdir);
     }
     closedir(busdir);
 
@@ -431,5 +456,5 @@
 
 usb_handle *usb_open(ifc_match_func callback)
 {
-    return find_usb_device("/dev/bus/usb", callback);
+    return find_usb_device("/sys/bus/usb/devices", callback);
 }
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index f432f6a..13b71ee 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -238,74 +238,16 @@
     return f;
 }
 
-/* Read a line of text till the next newline character.
- * If no newline is found before the buffer is full, continue reading till a new line is seen,
- * then return an empty buffer.  This effectively ignores lines that are too long.
- * On EOF, return null.
- */
-static char *fs_getline(char *buf, int size, FILE *file)
-{
-    int cnt = 0;
-    int eof = 0;
-    int eol = 0;
-    int c;
-
-    if (size < 1) {
-        return NULL;
-    }
-
-    while (cnt < (size - 1)) {
-        c = getc(file);
-        if (c == EOF) {
-            eof = 1;
-            break;
-        }
-
-        *(buf + cnt) = c;
-        cnt++;
-
-        if (c == '\n') {
-            eol = 1;
-            break;
-        }
-    }
-
-    /* Null terminate what we've read */
-    *(buf + cnt) = '\0';
-
-    if (eof) {
-        if (cnt) {
-            return buf;
-        } else {
-            return NULL;
-        }
-    } else if (eol) {
-        return buf;
-    } else {
-        /* The line is too long.  Read till a newline or EOF.
-         * If EOF, return null, if newline, return an empty buffer.
-         */
-        while(1) {
-            c = getc(file);
-            if (c == EOF) {
-                return NULL;
-            } else if (c == '\n') {
-                *buf = '\0';
-                return buf;
-            }
-        }
-    }
-}
-
 struct fstab *fs_mgr_read_fstab(const char *fstab_path)
 {
     FILE *fstab_file;
     int cnt, entries;
-    int len;
-    char line[256];
+    ssize_t len;
+    size_t alloc_len = 0;
+    char *line = NULL;
     const char *delim = " \t";
     char *save_ptr, *p;
-    struct fstab *fstab;
+    struct fstab *fstab = NULL;
     struct fstab_rec *recs;
     struct fs_mgr_flag_values flag_vals;
 #define FS_OPTIONS_LEN 1024
@@ -318,9 +260,8 @@
     }
 
     entries = 0;
-    while (fs_getline(line, sizeof(line), fstab_file)) {
+    while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
         /* if the last character is a newline, shorten the string by 1 byte */
-        len = strlen(line);
         if (line[len - 1] == '\n') {
             line[len - 1] = '\0';
         }
@@ -337,7 +278,7 @@
 
     if (!entries) {
         ERROR("No entries found in fstab\n");
-        return 0;
+        goto err;
     }
 
     /* Allocate and init the fstab structure */
@@ -349,9 +290,8 @@
     fseek(fstab_file, 0, SEEK_SET);
 
     cnt = 0;
-    while (fs_getline(line, sizeof(line), fstab_file)) {
+    while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
         /* if the last character is a newline, shorten the string by 1 byte */
-        len = strlen(line);
         if (line[len - 1] == '\n') {
             line[len - 1] = '\0';
         }
@@ -376,25 +316,25 @@
 
         if (!(p = strtok_r(line, delim, &save_ptr))) {
             ERROR("Error parsing mount source\n");
-            return 0;
+            goto err;
         }
         fstab->recs[cnt].blk_device = strdup(p);
 
         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
             ERROR("Error parsing mount_point\n");
-            return 0;
+            goto err;
         }
         fstab->recs[cnt].mount_point = strdup(p);
 
         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
             ERROR("Error parsing fs_type\n");
-            return 0;
+            goto err;
         }
         fstab->recs[cnt].fs_type = strdup(p);
 
         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
             ERROR("Error parsing mount_flags\n");
-            return 0;
+            goto err;
         }
         tmp_fs_options[0] = '\0';
         fstab->recs[cnt].flags = parse_flags(p, mount_flags, NULL,
@@ -409,7 +349,7 @@
 
         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
             ERROR("Error parsing fs_mgr_options\n");
-            return 0;
+            goto err;
         }
         fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
                                                     &flag_vals, NULL, 0);
@@ -422,8 +362,15 @@
         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)
@@ -442,7 +389,6 @@
         free(fstab->recs[i].fs_options);
         free(fstab->recs[i].key_loc);
         free(fstab->recs[i].label);
-        i++;
     }
 
     /* Free the fstab_recs array created by calloc(3) */
diff --git a/include/backtrace/backtrace.h b/include/backtrace/backtrace.h
new file mode 100644
index 0000000..b6bff38
--- /dev/null
+++ b/include/backtrace/backtrace.h
@@ -0,0 +1,104 @@
+/*
+ * 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 _BACKTRACE_H
+#define _BACKTRACE_H
+
+#include <sys/types.h>
+#include <stdbool.h>
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_BACKTRACE_FRAMES 64
+
+typedef struct backtrace_map_info {
+  struct backtrace_map_info* next;
+  uintptr_t start;
+  uintptr_t end;
+  bool is_readable;
+  bool is_writable;
+  bool is_executable;
+  char name[];
+} backtrace_map_info_t;
+
+typedef struct {
+  uintptr_t pc;           /* The absolute pc. */
+  uintptr_t sp;           /* The top of the stack. */
+  size_t stack_size;      /* The size of the stack, zero indicate an unknown stack size. */
+  const char* map_name;   /* The name of the map to which this pc belongs, NULL indicates the pc doesn't belong to a known map. */
+  uintptr_t map_offset;   /* pc relative to the start of the map, only valid if map_name is not NULL. */
+  char* proc_name;        /* The function name associated with this pc, NULL if not found. */
+  uintptr_t proc_offset;  /* pc relative to the start of the procedure, only valid if proc_name is not NULL. */
+} backtrace_frame_data_t;
+
+typedef struct {
+  backtrace_frame_data_t frames[MAX_BACKTRACE_FRAMES];
+  size_t num_frames;
+
+  pid_t tid;
+  backtrace_map_info_t* map_info_list;
+  void* private_data;
+} backtrace_t;
+
+/* Gather the backtrace data for tid and fill in the backtrace structure.
+ * If tid < 0, then gather the backtrace for the current thread.
+ */
+bool backtrace_get_data(backtrace_t* backtrace, pid_t tid);
+
+/* Free any memory associated with the backtrace structure. */
+void backtrace_free_data(backtrace_t* backtrace);
+
+/* Read data at a specific address for a process. */
+bool backtrace_read_word(
+    const backtrace_t* backtrace, uintptr_t ptr, uint32_t* value);
+
+/* Get information about the map associated with a pc. If NULL is
+ * returned, then map_start is not set.
+ */
+const char* backtrace_get_map_info(
+    const backtrace_t* backtrace, uintptr_t pc, uintptr_t* map_start);
+
+/* Get the procedure name and offest given the pc. If NULL is returned,
+ * then proc_offset is not set. The returned string is allocated using
+ * malloc and must be freed by the caller.
+ */
+char* backtrace_get_proc_name(
+    const backtrace_t* backtrace, uintptr_t pc, uintptr_t* proc_offset);
+
+/* Loads memory map from /proc/<tid>/maps. If tid < 0, then load the memory
+ * map for the current process.
+ */
+backtrace_map_info_t* backtrace_create_map_info_list(pid_t tid);
+
+/* Frees memory associated with the map list. */
+void backtrace_destroy_map_info_list(backtrace_map_info_t* map_info_list);
+
+/* Finds the memory map that contains the specified pc. */
+const backtrace_map_info_t* backtrace_find_map_info(
+    const backtrace_map_info_t* map_info_list, uintptr_t pc);
+
+/* Create a formatted line of backtrace information for a single frame. */
+void backtrace_format_frame_data(
+    const backtrace_frame_data_t* frame, size_t frame_num, char *buf, size_t buf_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BACKTRACE_H */
diff --git a/include/cutils/list.h b/include/cutils/list.h
index 3881fc9..72395f4 100644
--- a/include/cutils/list.h
+++ b/include/cutils/list.h
@@ -44,6 +44,11 @@
 #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; \
+         node != (list); \
+         node = next, next = node->next)
+
 void list_init(struct listnode *list);
 void list_add_tail(struct listnode *list, struct listnode *item);
 void list_remove(struct listnode *item);
diff --git a/init/devices.c b/init/devices.c
index 1893642..af88c5f 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -33,6 +33,7 @@
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 #include <selinux/android.h>
+#include <selinux/avc.h>
 
 #include <private/android_filesystem_config.h>
 #include <sys/time.h>
@@ -830,6 +831,15 @@
         struct uevent uevent;
         parse_event(msg, &uevent);
 
+        if (sehandle && selinux_status_updated() > 0) {
+            struct selabel_handle *sehandle2;
+            sehandle2 = selinux_android_file_context_handle();
+            if (sehandle2) {
+                selabel_close(sehandle);
+                sehandle = sehandle2;
+            }
+        }
+
         handle_device_event(&uevent);
         handle_firmware_event(&uevent);
     }
@@ -896,6 +906,7 @@
     sehandle = NULL;
     if (is_selinux_enabled() > 0) {
         sehandle = selinux_android_file_context_handle();
+        selinux_status_open(true);
     }
 
     /* is 256K enough? udev uses 16MB! */
diff --git a/init/init.c b/init/init.c
index 94a2011..feac8ad 100644
--- a/init/init.c
+++ b/init/init.c
@@ -250,14 +250,12 @@
         for (ei = svc->envvars; ei; ei = ei->next)
             add_environment(ei->name, ei->value);
 
-        setsockcreatecon(scon);
-
         for (si = svc->sockets; si; si = si->next) {
             int socket_type = (
                     !strcmp(si->type, "stream") ? SOCK_STREAM :
                         (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
             int s = create_socket(si->name, socket_type,
-                                  si->perm, si->uid, si->gid);
+                                  si->perm, si->uid, si->gid, si->socketcon ?: scon);
             if (s >= 0) {
                 publish_socket(si->name, s);
             }
@@ -265,7 +263,6 @@
 
         freecon(scon);
         scon = NULL;
-        setsockcreatecon(NULL);
 
         if (svc->ioprio_class != IoSchedClass_NONE) {
             if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) {
diff --git a/init/init.h b/init/init.h
index aa6a4ab..3928d52 100644
--- a/init/init.h
+++ b/init/init.h
@@ -55,6 +55,7 @@
     uid_t uid;
     gid_t gid;
     int perm;
+    const char *socketcon;
 };
 
 struct svcenvinfo {
diff --git a/init/init_parser.c b/init/init_parser.c
index 776c699..667c7ab 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -552,12 +552,14 @@
                 if (length > PROP_NAME_MAX) {
                     ERROR("property name too long in trigger %s", act->name);
                 } else {
+                    int ret;
                     memcpy(prop_name, name, length);
                     prop_name[length] = 0;
 
                     /* does the property exist, and match the trigger value? */
-                    property_get(prop_name, value);
-                    if (!strcmp(equals + 1, value) ||!strcmp(equals + 1, "*")) {
+                    ret = property_get(prop_name, value);
+                    if (ret > 0 && (!strcmp(equals + 1, value) ||
+                                    !strcmp(equals + 1, "*"))) {
                         action_add_queue_tail(act);
                     }
                 }
@@ -771,7 +773,7 @@
         svc->envvars = ei;
         break;
     }
-    case K_socket: {/* name type perm [ uid gid ] */
+    case K_socket: {/* name type perm [ uid gid context ] */
         struct socketinfo *si;
         if (nargs < 4) {
             parse_error(state, "socket option requires name, type, perm arguments\n");
@@ -794,6 +796,8 @@
             si->uid = decode_uid(args[4]);
         if (nargs > 5)
             si->gid = decode_uid(args[5]);
+        if (nargs > 6)
+            si->socketcon = args[6];
         si->next = svc->sockets;
         svc->sockets = si;
         break;
diff --git a/init/property_service.c b/init/property_service.c
index 9ac2781..c370769 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -81,6 +81,7 @@
     { "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 },
@@ -92,6 +93,7 @@
     { "persist.sys.",     AID_SYSTEM,   0 },
     { "persist.service.", AID_SYSTEM,   0 },
     { "persist.security.", AID_SYSTEM,   0 },
+    { "persist.gps.",      AID_GPS,      0 },
     { "persist.service.bdroid.", AID_BLUETOOTH,   0 },
     { "selinux."         , AID_SYSTEM,   0 },
     { NULL, 0, 0 }
@@ -437,10 +439,13 @@
     *sz = pa_workspace.size;
 }
 
-static void load_properties(char *data)
+static void load_properties(char *data, char *prefix)
 {
     char *key, *value, *eol, *sol, *tmp;
+    size_t plen;
 
+    if (prefix)
+        plen = strlen(prefix);
     sol = data;
     while((eol = strchr(sol, '\n'))) {
         key = sol;
@@ -456,6 +461,9 @@
         tmp = value - 2;
         while((tmp > key) && isspace(*tmp)) *tmp-- = 0;
 
+        if (prefix && strncmp(key, prefix, plen))
+            continue;
+
         while(isspace(*value)) value++;
         tmp = eol - 2;
         while((tmp > value) && isspace(*tmp)) *tmp-- = 0;
@@ -464,7 +472,7 @@
     }
 }
 
-static void load_properties_from_file(const char *fn)
+static void load_properties_from_file(const char *fn, char *prefix)
 {
     char *data;
     unsigned sz;
@@ -472,7 +480,7 @@
     data = read_file(fn, &sz);
 
     if(data != 0) {
-        load_properties(data);
+        load_properties(data, prefix);
         free(data);
     }
 }
@@ -545,7 +553,7 @@
 
 void property_load_boot_defaults(void)
 {
-    load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT);
+    load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT, NULL);
 }
 
 int properties_inited(void)
@@ -560,7 +568,7 @@
 
     ret = property_get("ro.debuggable", debuggable);
     if (ret && (strcmp(debuggable, "1") == 0)) {
-        load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);
+        load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE, NULL);
     }
 #endif /* ALLOW_LOCAL_PROP_OVERRIDE */
 }
@@ -582,13 +590,14 @@
 {
     int fd;
 
-    load_properties_from_file(PROP_PATH_SYSTEM_BUILD);
-    load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);
+    load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);
+    load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT, NULL);
+    load_properties_from_file(PROP_PATH_FACTORY, "ro.");
     load_override_properties();
     /* Read persistent properties after all default values have been loaded. */
     load_persistent_properties();
 
-    fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0);
+    fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0, NULL);
     if(fd < 0) return;
     fcntl(fd, F_SETFD, FD_CLOEXEC);
     fcntl(fd, F_SETFL, O_NONBLOCK);
diff --git a/init/readme.txt b/init/readme.txt
index 7a5997d..1e8c392 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -70,10 +70,13 @@
 setenv <name> <value>
    Set the environment variable <name> to <value> in the launched process.
 
-socket <name> <type> <perm> [ <user> [ <group> ] ]
+socket <name> <type> <perm> [ <user> [ <group> [ <context> ] ] ]
    Create a unix domain socket named /dev/socket/<name> and pass
    its fd to the launched process.  <type> must be "dgram", "stream" or "seqpacket".
    User and group default to 0.
+   Context is the SELinux security context for the socket.
+   It defaults to the service security context, as specified by seclabel or
+   computed based on the service executable file security context.
 
 user <username>
    Change to username before exec'ing this service.
diff --git a/init/util.c b/init/util.c
index 1908b3a..9aaa77d 100644
--- a/init/util.c
+++ b/init/util.c
@@ -84,11 +84,15 @@
  * daemon. We communicate the file descriptor's value via the environment
  * variable ANDROID_SOCKET_ENV_PREFIX<name> ("ANDROID_SOCKET_foo").
  */
-int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid)
+int create_socket(const char *name, int type, mode_t perm, uid_t uid,
+                  gid_t gid, const char *socketcon)
 {
     struct sockaddr_un addr;
     int fd, ret;
-    char *secon;
+    char *filecon;
+
+    if (socketcon)
+        setsockcreatecon(socketcon);
 
     fd = socket(PF_UNIX, type, 0);
     if (fd < 0) {
@@ -96,6 +100,9 @@
         return -1;
     }
 
+    if (socketcon)
+        setsockcreatecon(NULL);
+
     memset(&addr, 0 , sizeof(addr));
     addr.sun_family = AF_UNIX;
     snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",
@@ -107,11 +114,11 @@
         goto out_close;
     }
 
-    secon = NULL;
+    filecon = NULL;
     if (sehandle) {
-        ret = selabel_lookup(sehandle, &secon, addr.sun_path, S_IFSOCK);
+        ret = selabel_lookup(sehandle, &filecon, addr.sun_path, S_IFSOCK);
         if (ret == 0)
-            setfscreatecon(secon);
+            setfscreatecon(filecon);
     }
 
     ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
@@ -121,7 +128,7 @@
     }
 
     setfscreatecon(NULL);
-    freecon(secon);
+    freecon(filecon);
 
     chown(addr.sun_path, uid, gid);
     chmod(addr.sun_path, perm);
@@ -398,7 +405,9 @@
 
 void get_hardware_name(char *hardware, unsigned int *revision)
 {
-    char data[1024];
+    const char *cpuinfo = "/proc/cpuinfo";
+    char *data = NULL;
+    size_t len = 0, limit = 1024;
     int fd, n;
     char *x, *hw, *rev;
 
@@ -406,14 +415,32 @@
     if (hardware[0])
         return;
 
-    fd = open("/proc/cpuinfo", O_RDONLY);
+    fd = open(cpuinfo, O_RDONLY);
     if (fd < 0) return;
 
-    n = read(fd, data, 1023);
-    close(fd);
-    if (n < 0) return;
+    for (;;) {
+        x = realloc(data, limit);
+        if (!x) {
+            ERROR("Failed to allocate memory to read %s\n", cpuinfo);
+            goto done;
+        }
+        data = x;
 
-    data[n] = 0;
+        n = read(fd, data + len, limit - len);
+        if (n < 0) {
+            ERROR("Failed reading %s: %s (%d)\n", cpuinfo, strerror(errno), errno);
+            goto done;
+        }
+        len += n;
+
+        if (len < limit)
+            break;
+
+        /* We filled the buffer, so increase size and loop to read more */
+        limit *= 2;
+    }
+
+    data[len] = 0;
     hw = strstr(data, "\nHardware");
     rev = strstr(data, "\nRevision");
 
@@ -438,18 +465,22 @@
             *revision = strtoul(x + 2, 0, 16);
         }
     }
+
+done:
+    close(fd);
+    free(data);
 }
 
 void import_kernel_cmdline(int in_qemu,
                            void (*import_kernel_nv)(char *name, int in_qemu))
 {
-    char cmdline[1024];
+    char cmdline[2048];
     char *ptr;
     int fd;
 
     fd = open("/proc/cmdline", O_RDONLY);
     if (fd >= 0) {
-        int n = read(fd, cmdline, 1023);
+        int n = read(fd, cmdline, sizeof(cmdline) - 1);
         if (n < 0) n = 0;
 
         /* get rid of trailing newline, it happens */
diff --git a/init/util.h b/init/util.h
index 6bca4e6..04b8129 100644
--- a/init/util.h
+++ b/init/util.h
@@ -26,7 +26,7 @@
 
 int mtd_name_to_number(const char *name);
 int create_socket(const char *name, int type, mode_t perm,
-                  uid_t uid, gid_t gid);
+                  uid_t uid, gid_t gid, const char *socketcon);
 void *read_file(const char *fn, unsigned *_sz);
 time_t gettime(void);
 unsigned int decode_uid(const char *s);
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
new file mode 100644
index 0000000..f7b084d
--- /dev/null
+++ b/libbacktrace/Android.mk
@@ -0,0 +1,176 @@
+LOCAL_PATH:= $(call my-dir)
+
+#----------------------------------------------------------------------------
+# The libbacktrace library using libunwind
+#----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	unwind.c \
+	unwind_remote.c \
+	unwind_local.c \
+	common.c \
+	demangle.c \
+	map_info.c \
+
+LOCAL_CFLAGS := \
+	-Wall \
+	-Wno-unused-parameter \
+	-Werror \
+	-std=gnu99 \
+
+LOCAL_MODULE := libbacktrace
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SHARED_LIBRARIES := \
+	liblog \
+	libunwind \
+	libunwind-ptrace \
+	libgccdemangle \
+
+LOCAL_C_INCLUDES := \
+	external/libunwind/include \
+
+# The libunwind code is not in the tree yet, so don't build this library yet.
+#include $(BUILD_SHARED_LIBRARY)
+
+#----------------------------------------------------------------------------
+# The libbacktrace library using libcorkscrew
+#----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	corkscrew.c \
+	common.c \
+	demangle.c \
+	map_info.c \
+
+LOCAL_CFLAGS := \
+	-Wall \
+	-Wno-unused-parameter \
+	-Werror \
+	-std=gnu99 \
+
+LOCAL_MODULE := libbacktrace
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SHARED_LIBRARIES := \
+	libcorkscrew \
+	libdl \
+	libgccdemangle \
+	liblog \
+
+include $(BUILD_SHARED_LIBRARY)
+
+#----------------------------------------------------------------------------
+# The host libbacktrace library using libcorkscrew
+#----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES += \
+	corkscrew.c \
+	common.c \
+	demangle.c \
+	map_info.c \
+
+LOCAL_CFLAGS += \
+	-Wall \
+	-Wno-unused-parameter \
+	-Werror \
+	-std=gnu99 \
+
+LOCAL_SHARED_LIBRARIES := \
+	liblog \
+	libcorkscrew \
+	libgccdemangle \
+	liblog \
+
+LOCAL_LDLIBS += \
+	-ldl \
+	-lrt \
+
+LOCAL_MODULE := libbacktrace
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+#----------------------------------------------------------------------------
+# 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 \
+
+include $(BUILD_SHARED_LIBRARY)
+
+#----------------------------------------------------------------------------
+# libbacktrace test executable
+#----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := backtrace_test
+LOCAL_MODULE_FLAGS := debug
+
+LOCAL_SRC_FILES := \
+	backtrace_test.c \
+
+LOCAL_CFLAGS += \
+	-std=gnu99 \
+
+LOCAL_SHARED_LIBRARIES := \
+	libbacktrace_test \
+	libbacktrace \
+
+include $(BUILD_EXECUTABLE)
+
+#----------------------------------------------------------------------------
+# Only linux-x86 host versions of libbacktrace supported.
+#----------------------------------------------------------------------------
+ifeq ($(HOST_OS)-$(HOST_ARCH),linux-x86)
+
+#----------------------------------------------------------------------------
+# 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 \
+
+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.c \
+
+LOCAL_CFLAGS += \
+	-std=gnu99 \
+
+LOCAL_SHARED_LIBRARIES := \
+	libbacktrace_test \
+	libbacktrace \
+
+include $(BUILD_HOST_EXECUTABLE)
+
+endif # HOST_OS-HOST_ARCH == linux-x86
diff --git a/libbacktrace/backtrace_test.c b/libbacktrace/backtrace_test.c
new file mode 100644
index 0000000..34d3519
--- /dev/null
+++ b/libbacktrace/backtrace_test.c
@@ -0,0 +1,217 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <backtrace/backtrace.h>
+
+#define FINISH(pid) dump_frames(&backtrace); if (pid < 0) exit(1); else return false;
+
+// Prototypes for functions in the test library.
+int test_level_one(int, int, int, int, bool (*)(pid_t));
+
+int test_recursive_call(int, bool (*)(pid_t));
+
+void dump_frames(const backtrace_t* backtrace) {
+  for (size_t i = 0; i < backtrace->num_frames; i++) {
+    printf("%zu ", i);
+    if (backtrace->frames[i].map_name) {
+      printf("%s", backtrace->frames[i].map_name);
+    } else {
+      printf("<unknown>");
+    }
+    if (backtrace->frames[i].proc_name) {
+      printf(" %s", backtrace->frames[i].proc_name);
+      if (backtrace->frames[i].proc_offset) {
+        printf("+%" PRIuPTR, backtrace->frames[i].proc_offset);
+      }
+    }
+    printf("\n");
+  }
+}
+
+bool check_frame(const backtrace_t* backtrace, size_t frame_num,
+                 const char* expected_name) {
+  if (backtrace->frames[frame_num].proc_name == NULL) {
+    printf("  Frame %zu function name expected %s, real value is NULL.\n",
+           frame_num, expected_name);
+    return false;
+  }
+  if (strcmp(backtrace->frames[frame_num].proc_name, expected_name) != 0) {
+    printf("  Frame %zu function name expected %s, real value is %s.\n",
+           frame_num, expected_name, backtrace->frames[frame_num].proc_name);
+    return false;
+  }
+  return true;
+}
+
+bool verify_level_backtrace(pid_t pid) {
+  const char* test_type;
+  if (pid < 0) {
+    test_type = "current";
+  } else {
+    test_type = "running";
+  }
+
+  backtrace_t backtrace;
+  if (!backtrace_get_data(&backtrace, pid)) {
+    printf("  backtrace_get_data failed on %s process.\n", test_type);
+    FINISH(pid);
+  }
+
+  if (backtrace.num_frames == 0) {
+    printf("  backtrace_get_data returned no frames for %s process.\n",
+           test_type);
+    FINISH(pid);
+  }
+
+  // Look through the frames starting at the highest to find the
+  // frame we want.
+  size_t frame_num = 0;
+  for (size_t i = backtrace.num_frames-1; i > 2; i--) {
+    if (backtrace.frames[i].proc_name != NULL &&
+        strcmp(backtrace.frames[i].proc_name, "test_level_one") == 0) {
+      frame_num = i;
+      break;
+    }
+  }
+  if (!frame_num) {
+    printf("  backtrace_get_data did not include the test_level_one frame.\n");
+    FINISH(pid);
+  }
+
+  if (!check_frame(&backtrace, frame_num, "test_level_one")) {
+    FINISH(pid);
+  }
+  if (!check_frame(&backtrace, frame_num-1, "test_level_two")) {
+    FINISH(pid);
+  }
+  if (!check_frame(&backtrace, frame_num-2, "test_level_three")) {
+    FINISH(pid);
+  }
+  if (!check_frame(&backtrace, frame_num-3, "test_level_four")) {
+    FINISH(pid);
+  }
+  backtrace_free_data(&backtrace);
+
+  return true;
+}
+
+bool verify_max_backtrace(pid_t pid) {
+  const char* test_type;
+  if (pid < 0) {
+    test_type = "current";
+  } else {
+    test_type = "running";
+  }
+
+  backtrace_t backtrace;
+  if (!backtrace_get_data(&backtrace, pid)) {
+    printf("  backtrace_get_data failed on %s process.\n", test_type);
+    FINISH(pid);
+  }
+
+  if (backtrace.num_frames != MAX_BACKTRACE_FRAMES) {
+    printf("  backtrace_get_data %s process max frame check failed:\n",
+           test_type);
+    printf("    Expected num frames to be %zu, found %zu\n",
+           MAX_BACKTRACE_FRAMES, backtrace.num_frames);
+    FINISH(pid);
+  }
+  backtrace_free_data(&backtrace);
+
+  return true;
+}
+
+void verify_proc_test(pid_t pid, bool (*verify_func)(pid_t)) {
+  printf("  Waiting 5 seconds for process to get to infinite loop.\n");
+  sleep(5);
+  if (ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) {
+    printf("Failed to attach to pid %d\n", pid);
+    kill(pid, SIGKILL);
+    exit(1);
+  }
+  bool pass = verify_func(pid);
+  if (ptrace(PTRACE_DETACH, pid, 0, 0) != 0) {
+    printf("Failed to detach from pid %d\n", pid);
+    kill(pid, SIGKILL);
+    exit(1);
+  }
+
+  kill(pid, SIGKILL);
+  int status;
+  if (waitpid(pid, &status, 0) != pid) {
+    printf("Forked process did not terminate properly.\n");
+    exit(1);
+  }
+
+  if (!pass) {
+    exit(1);
+  }
+}
+
+int main() {
+  printf("Running level test on current process...\n");
+  int value = test_level_one(1, 2, 3, 4, verify_level_backtrace);
+  if (value == 0) {
+    printf("This should never happen.\n");
+    exit(1);
+  }
+  printf("  Passed.\n");
+
+  printf("Running max level test on current process...\n");
+  value = test_recursive_call(MAX_BACKTRACE_FRAMES+10, verify_max_backtrace);
+  if (value == 0) {
+    printf("This should never happen.\n");
+    exit(1);
+  }
+  printf("  Passed.\n");
+
+  printf("Running level test on process...\n");
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    value = test_level_one(1, 2, 3, 4, NULL);
+    if (value == 0) {
+      printf("This should never happen.\n");
+    }
+    exit(1);
+  }
+  verify_proc_test(pid, verify_level_backtrace);
+  printf("  Passed.\n");
+
+  printf("Running max frame test on process...\n");
+  if ((pid = fork()) == 0) {
+    value = test_recursive_call(MAX_BACKTRACE_FRAMES+10, NULL);
+    if (value == 0) {
+      printf("This should never happen.\n");
+    }
+    exit(1);
+  }
+  verify_proc_test(pid, verify_max_backtrace);
+  printf("  Passed.\n");
+
+  printf("All tests passed.\n");
+  return 0;
+}
diff --git a/libbacktrace/backtrace_testlib.c b/libbacktrace/backtrace_testlib.c
new file mode 100644
index 0000000..9400549
--- /dev/null
+++ b/libbacktrace/backtrace_testlib.c
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#include <stdbool.h>
+#include <unistd.h>
+
+int test_level_four(int one, int two, int three, int four,
+                    bool (*callback_func)(pid_t)) {
+  if (callback_func != NULL) {
+    callback_func(-1);
+  } else {
+    while (1) {
+    }
+  }
+  return one + two + three + four;
+}
+
+int test_level_three(int one, int two, int three, int four,
+                     bool (*callback_func)(pid_t)) {
+  return test_level_four(one+3, two+6, three+9, four+12, callback_func) + 3;
+}
+
+int test_level_two(int one, int two, int three, int four,
+                   bool (*callback_func)(pid_t)) {
+  return test_level_three(one+2, two+4, three+6, four+8, callback_func) + 2;
+}
+
+int test_level_one(int one, int two, int three, int four,
+                   bool (*callback_func)(pid_t)) {
+  return test_level_two(one+1, two+2, three+3, four+4, callback_func) + 1;
+}
+
+int test_recursive_call(int level, bool (*callback_func)(pid_t)) {
+  if (level > 0) {
+    return test_recursive_call(level - 1, callback_func) + level;
+  } else if (callback_func != NULL) {
+    callback_func(-1);
+  } else {
+    while (1) {
+    }
+  }
+  return 0;
+}
diff --git a/libbacktrace/common.c b/libbacktrace/common.c
new file mode 100644
index 0000000..20786f4
--- /dev/null
+++ b/libbacktrace/common.c
@@ -0,0 +1,113 @@
+/*
+ * 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 <errno.h>
+#include <stdlib.h>
+#include <sys/ptrace.h>
+#include <inttypes.h>
+
+#include <cutils/log.h>
+#include <backtrace/backtrace.h>
+
+#include "common.h"
+
+bool backtrace_read_word(const backtrace_t* backtrace, uintptr_t ptr,
+                         uint32_t* out_value) {
+  if (ptr & 3) {
+    ALOGW("backtrace_read_word: invalid pointer %p", (void*)ptr);
+    *out_value = (uint32_t)-1;
+    return false;
+  }
+
+  // Check if reading from the current process, or a different process.
+  if (backtrace->tid < 0) {
+    const backtrace_map_info_t* map_info = backtrace_find_map_info(backtrace->map_info_list, ptr);
+    if (map_info && map_info->is_readable) {
+      *out_value = *(uint32_t*)ptr;
+      return true;
+    } else {
+      ALOGW("backtrace_read_word: pointer %p not in a readbale map", (void*)ptr);
+      *out_value = (uint32_t)-1;
+      return false;
+    }
+  } else {
+#if defined(__APPLE__)
+    ALOGW("read_word: MacOS does not support reading from another pid.\n");
+    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, backtrace->tid, (void*)ptr, NULL);
+    if (*out_value == (uint32_t)-1 && errno) {
+      ALOGW("try_get_word: invalid pointer 0x%08x reading from tid %d, "
+            "ptrace() errno=%d", ptr, backtrace->tid, errno);
+      return false;
+    }
+    return true;
+  }
+#endif
+}
+
+const char *backtrace_get_map_info(
+    const backtrace_t* backtrace, uintptr_t pc, uintptr_t* start_pc) {
+  const backtrace_map_info_t* map_info = backtrace_find_map_info(backtrace->map_info_list, pc);
+  if (map_info) {
+    if (start_pc) {
+      *start_pc = map_info->start;
+    }
+    return map_info->name;
+  }
+  return NULL;
+}
+
+void backtrace_format_frame_data(
+    const backtrace_frame_data_t* frame, size_t frame_num, char *buf, size_t buf_size) {
+  uintptr_t relative_pc;
+  const char* map_name;
+  if (frame->map_name) {
+    map_name = frame->map_name;
+  } else {
+    map_name = "<unknown>";
+  }
+  if (frame->map_offset) {
+    relative_pc = frame->map_offset;
+  } else {
+    relative_pc = frame->pc;
+  }
+  if (frame->proc_name && frame->proc_offset) {
+    snprintf(buf, buf_size, "#%02zu pc %0*" PRIxPTR "  %s (%s+%" PRIuPTR ")",
+             frame_num, (int)sizeof(uintptr_t)*2, relative_pc, map_name,
+             frame->proc_name, frame->proc_offset);
+  } else if (frame->proc_name) {
+    snprintf(buf, buf_size, "#%02zu pc %0*" PRIxPTR "  %s (%s)", frame_num,
+             (int)sizeof(uintptr_t)*2, relative_pc, map_name, frame->proc_name);
+  } else {
+    snprintf(buf, buf_size, "#%02zu pc %0*" PRIxPTR "  %s", frame_num,
+             (int)sizeof(uintptr_t)*2, relative_pc, map_name);
+  }
+}
+
+void free_frame_data(backtrace_t* backtrace) {
+  for (size_t i = 0; i < backtrace->num_frames; i++) {
+    if (backtrace->frames[i].proc_name) {
+      free(backtrace->frames[i].proc_name);
+    }
+  }
+  backtrace->num_frames = 0;
+}
diff --git a/libbacktrace/common.h b/libbacktrace/common.h
new file mode 100644
index 0000000..9eef964
--- /dev/null
+++ b/libbacktrace/common.h
@@ -0,0 +1,25 @@
+/*
+ * 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 _COMMON_H
+#define _COMMON_H
+
+#include <backtrace/backtrace.h>
+
+/* Common routine to free any data allocated to store frame information. */
+void free_frame_data(backtrace_t* backtrace);
+
+#endif /* _COMMON_H */
diff --git a/libbacktrace/corkscrew.c b/libbacktrace/corkscrew.c
new file mode 100644
index 0000000..899409a
--- /dev/null
+++ b/libbacktrace/corkscrew.c
@@ -0,0 +1,130 @@
+/*
+ * 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 <string.h>
+
+#include <cutils/log.h>
+#include <backtrace/backtrace.h>
+
+#include <corkscrew/backtrace.h>
+
+#define __USE_GNU
+#include <dlfcn.h>
+
+#include "common.h"
+#include "demangle.h"
+
+bool backtrace_get_data(backtrace_t* backtrace, pid_t tid) {
+  backtrace->num_frames = 0;
+  backtrace->tid = tid;
+  backtrace->private_data = NULL;
+  backtrace->map_info_list = backtrace_create_map_info_list(tid);
+
+  backtrace_frame_t frames[MAX_BACKTRACE_FRAMES];
+  ssize_t num_frames;
+  if (tid < 0) {
+    // Get data for the current thread.
+    num_frames = unwind_backtrace(frames, 0, MAX_BACKTRACE_FRAMES);
+  } else {
+    // Get data for a different thread.
+    ptrace_context_t* ptrace_context = load_ptrace_context(tid);
+    backtrace->private_data = ptrace_context;
+
+    num_frames = unwind_backtrace_ptrace(
+        tid, ptrace_context, frames, 0, MAX_BACKTRACE_FRAMES);
+  }
+  if (num_frames < 0) {
+      ALOGW("backtrace_get_data: unwind_backtrace_ptrace failed %d\n",
+            num_frames);
+      backtrace_free_data(backtrace);
+      return false;
+  }
+
+  backtrace->num_frames = num_frames;
+  backtrace_frame_data_t* frame;
+  uintptr_t map_start;
+  for (size_t i = 0; i < backtrace->num_frames; i++) {
+    frame = &backtrace->frames[i];
+    frame->pc = frames[i].absolute_pc;
+    frame->sp = frames[i].stack_top;
+    frame->stack_size = frames[i].stack_size;
+
+    frame->map_offset = 0;
+    frame->map_name = backtrace_get_map_info(backtrace, frame->pc, &map_start);
+    if (frame->map_name) {
+      frame->map_offset = frame->pc - map_start;
+    }
+
+    frame->proc_offset = 0;
+    frame->proc_name = backtrace_get_proc_name(backtrace, frame->pc, &frame->proc_offset);
+  }
+
+  return true;
+}
+
+void backtrace_free_data(backtrace_t* backtrace) {
+  free_frame_data(backtrace);
+
+  if (backtrace->map_info_list) {
+    backtrace_destroy_map_info_list(backtrace->map_info_list);
+    backtrace->map_info_list = NULL;
+  }
+
+  if (backtrace->private_data) {
+    ptrace_context_t* ptrace_context = (ptrace_context_t*)backtrace->private_data;
+    free_ptrace_context(ptrace_context);
+    backtrace->private_data = NULL;
+  }
+}
+
+char* backtrace_get_proc_name(const backtrace_t* backtrace, uintptr_t pc,
+    uintptr_t* offset) {
+  const char* symbol_name = NULL;
+  *offset = 0;
+  if (backtrace->tid < 0) {
+    // Get information about the current thread.
+    Dl_info info;
+    const backtrace_map_info_t* map_info;
+    map_info = backtrace_find_map_info(backtrace->map_info_list, pc);
+    if (map_info && dladdr((const void*)pc, &info) && info.dli_sname) {
+      *offset = pc - map_info->start - (uintptr_t)info.dli_saddr + (uintptr_t)info.dli_fbase;
+      symbol_name = info.dli_sname;
+    }
+  } else {
+    // Get information about a different thread.
+    ptrace_context_t* ptrace_context = (ptrace_context_t*)backtrace->private_data;
+    const map_info_t* map_info;
+    const symbol_t* symbol;
+    find_symbol_ptrace(ptrace_context, pc, &map_info, &symbol);
+    if (symbol) {
+      if (map_info) {
+        *offset = pc - map_info->start - symbol->start;
+      }
+      symbol_name = symbol->name;
+    }
+  }
+
+  char* name = NULL;
+  if (symbol_name) {
+    name = demangle_symbol_name(symbol_name);
+    if (!name) {
+      name = strdup(symbol_name);
+    }
+  }
+  return name;
+}
diff --git a/libbacktrace/demangle.c b/libbacktrace/demangle.c
new file mode 100644
index 0000000..de9a460
--- /dev/null
+++ b/libbacktrace/demangle.c
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#include <sys/types.h>
+
+#include "demangle.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/libbacktrace/demangle.h b/libbacktrace/demangle.h
new file mode 100644
index 0000000..a5318ac
--- /dev/null
+++ b/libbacktrace/demangle.h
@@ -0,0 +1,25 @@
+/*
+ * 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 _DEMANGLE_H
+#define _DEMANGLE_H
+
+/* Called to demangle a symbol name to be printed. Returns an allocated
+ * string that must be freed by the caller.
+ */
+char* demangle_symbol_name(const char* name);
+
+#endif /* _DEMANGLE_H */
diff --git a/libbacktrace/map_info.c b/libbacktrace/map_info.c
new file mode 100644
index 0000000..9cc6e01
--- /dev/null
+++ b/libbacktrace/map_info.c
@@ -0,0 +1,173 @@
+/*
+ * 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.
+ */
+
+#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>
+
+#include <backtrace/backtrace.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 backtrace_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);
+
+  backtrace_map_info_t* mi = calloc(1, sizeof(backtrace_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';
+    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;
+}
+
+backtrace_map_info_t* backtrace_create_map_info_list(pid_t pid) {
+  char cmd[1024];
+  if (pid < 0) {
+    pid = getpid();
+  }
+  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];
+  backtrace_map_info_t* milist = NULL;
+  while (fgets(line, sizeof(line), fp) != NULL) {
+    backtrace_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 backtrace_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;
+  }
+
+  backtrace_map_info_t* mi = calloc(1, sizeof(backtrace_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';
+    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;
+}
+
+backtrace_map_info_t* backtrace_create_map_info_list(pid_t tid) {
+  char path[PATH_MAX];
+  char line[1024];
+  FILE* fp;
+  backtrace_map_info_t* milist = NULL;
+
+  if (tid < 0) {
+    tid = getpid();
+  }
+  snprintf(path, PATH_MAX, "/proc/%d/maps", tid);
+  fp = fopen(path, "r");
+  if (fp) {
+    while(fgets(line, sizeof(line), fp)) {
+      backtrace_map_info_t* mi = parse_maps_line(line);
+      if (mi) {
+        mi->next = milist;
+        milist = mi;
+      }
+    }
+    fclose(fp);
+  }
+  return milist;
+}
+
+#endif
+
+void backtrace_destroy_map_info_list(backtrace_map_info_t* milist) {
+  while (milist) {
+    backtrace_map_info_t* next = milist->next;
+    free(milist);
+    milist = next;
+  }
+}
+
+const backtrace_map_info_t* backtrace_find_map_info(
+    const backtrace_map_info_t* milist, uintptr_t addr) {
+  const backtrace_map_info_t* mi = milist;
+  while (mi && !(addr >= mi->start && addr < mi->end)) {
+    mi = mi->next;
+  }
+  return mi;
+}
diff --git a/libbacktrace/stubs.c b/libbacktrace/stubs.c
new file mode 100644
index 0000000..1741601
--- /dev/null
+++ b/libbacktrace/stubs.c
@@ -0,0 +1,53 @@
+/*
+ * 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 <cutils/log.h>
+#include <backtrace/backtrace.h>
+
+bool backtrace_get_data(backtrace_t* backtrace, pid_t tid) {
+  ALOGW("backtrace_get_data: unsupported architecture.\n");
+  return true;
+}
+
+void backtrace_free_data(backtrace_t* backtrace) {
+  ALOGW("backtrace_free_data: unsupported architecture.\n");
+}
+
+bool backtrace_read_word(const backtrace_t* backtrace, uintptr_t ptr,
+                         uint32_t* out_value) {
+  ALOGW("backtrace_read_word: unsupported architecture.\n");
+  return false;
+}
+
+const char *backtrace_get_map_info(const backtrace_t* backtrace,
+    uintptr_t pc, uintptr_t* start_pc) {
+  ALOGW("backtrace_get_map_info: unsupported architecture.\n");
+  return NULL;
+}
+
+char* backtrace_get_proc_name(const backtrace_t* backtrace, uintptr_t pc,
+    uintptr_t* offset) {
+  ALOGW("backtrace_get_proc_name: unsupported architecture.\n");
+  return NULL;
+}
+
+void backtrace_format_frame_data(
+    const backtrace_frame_data_t* frame, size_t frame_num, char *buf, size_t buf_size) {
+  ALOGW("backtrace_format_frame_data: unsupported architecture.\n");
+  buf[0] = '\0';
+}
diff --git a/libbacktrace/unwind.c b/libbacktrace/unwind.c
new file mode 100644
index 0000000..f75e518
--- /dev/null
+++ b/libbacktrace/unwind.c
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#include <backtrace/backtrace.h>
+
+#include "common.h"
+#include "unwind.h"
+
+bool backtrace_get_data(backtrace_t* backtrace, pid_t tid) {
+  backtrace->num_frames = 0;
+  backtrace->tid = tid;
+
+  backtrace->map_info_list = backtrace_create_map_info_list(tid);
+  if (tid < 0) {
+    return local_get_data(backtrace);
+  } else {
+    return remote_get_data(backtrace);
+  }
+}
+
+/* Free any memory related to the frame data. */
+void backtrace_free_data(backtrace_t* backtrace) {
+  free_frame_data(backtrace);
+
+  if (backtrace->map_info_list) {
+    backtrace_destroy_map_info_list(backtrace->map_info_list);
+    backtrace->map_info_list = NULL;
+  }
+
+  if (backtrace->tid < 0) {
+    local_free_data(backtrace);
+  } else {
+    remote_free_data(backtrace);
+  }
+}
+
+char* backtrace_get_proc_name(const backtrace_t* backtrace, uintptr_t pc,
+                              uintptr_t* offset) {
+  if (backtrace->tid < 0) {
+    return local_get_proc_name(backtrace, pc, offset);
+  } else {
+    return remote_get_proc_name(backtrace, pc, offset);
+  }
+}
diff --git a/libbacktrace/unwind.h b/libbacktrace/unwind.h
new file mode 100644
index 0000000..9ba96a4
--- /dev/null
+++ b/libbacktrace/unwind.h
@@ -0,0 +1,34 @@
+/*
+ * 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 _UNWIND_H
+#define _UNWIND_H
+
+bool local_get_data(backtrace_t* backtrace);
+
+void local_free_data(backtrace_t* backtrace);
+
+char* local_get_proc_name(const backtrace_t* backtrace, uintptr_t pc,
+                          uintptr_t* offset);
+
+bool remote_get_data(backtrace_t* backtrace);
+
+void remote_free_data(backtrace_t* backtrace);
+
+char* remote_get_proc_name(const backtrace_t* backtrace, uintptr_t pc,
+                           uintptr_t* offset);
+
+#endif /* _UNWIND_H */
diff --git a/libbacktrace/unwind_local.c b/libbacktrace/unwind_local.c
new file mode 100644
index 0000000..e0b72d8
--- /dev/null
+++ b/libbacktrace/unwind_local.c
@@ -0,0 +1,123 @@
+/*
+ * 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 <string.h>
+
+#include <cutils/log.h>
+#include <backtrace/backtrace.h>
+
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#include <libunwind-ptrace.h>
+
+#include "common.h"
+#include "demangle.h"
+
+static bool local_get_frames(backtrace_t* backtrace) {
+  unw_context_t* context = (unw_context_t*)backtrace->private_data;
+  unw_cursor_t cursor;
+
+  int ret = unw_getcontext(context);
+  if (ret < 0) {
+    ALOGW("local_get_frames: unw_getcontext failed %d\n", ret);
+    return false;
+  }
+
+  ret = unw_init_local(&cursor, context);
+  if (ret < 0) {
+    ALOGW("local_get_frames: unw_init_local failed %d\n", ret);
+    return false;
+  }
+
+  backtrace_frame_data_t* frame;
+  bool returnValue = true;
+  backtrace->num_frames = 0;
+  uintptr_t map_start;
+  do {
+    frame = &backtrace->frames[backtrace->num_frames];
+    frame->stack_size = 0;
+    frame->map_name = NULL;
+    frame->map_offset = 0;
+    frame->proc_name = NULL;
+    frame->proc_offset = 0;
+
+    ret = unw_get_reg(&cursor, UNW_REG_IP, &frame->pc);
+    if (ret < 0) {
+      ALOGW("get_frames: Failed to read IP %d\n", ret);
+      returnValue = false;
+      break;
+    }
+    ret = unw_get_reg(&cursor, UNW_REG_SP, &frame->sp);
+    if (ret < 0) {
+      ALOGW("get_frames: Failed to read IP %d\n", ret);
+      returnValue = false;
+      break;
+    }
+    if (backtrace->num_frames) {
+      backtrace_frame_data_t* prev = &backtrace->frames[backtrace->num_frames-1];
+      prev->stack_size = frame->sp - prev->sp;
+    }
+
+    frame->proc_name = backtrace_get_proc_name(backtrace, frame->pc, &frame->proc_offset);
+
+    frame->map_name = backtrace_get_map_info(backtrace, frame->pc, &map_start);
+    if (frame->map_name) {
+      frame->map_offset = frame->pc - map_start;
+    }
+
+    backtrace->num_frames++;
+    ret = unw_step (&cursor);
+  } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES);
+
+  return returnValue;
+}
+
+bool local_get_data(backtrace_t* backtrace) {
+  unw_context_t *context = (unw_context_t*)malloc(sizeof(unw_context_t));
+  backtrace->private_data = context;
+
+  if (!local_get_frames(backtrace)) {
+    backtrace_free_data(backtrace);
+    return false;
+  }
+
+  return true;
+}
+
+void local_free_data(backtrace_t* backtrace) {
+  if (backtrace->private_data) {
+    free(backtrace->private_data);
+    backtrace->private_data = NULL;
+  }
+}
+
+char* local_get_proc_name(const backtrace_t* backtrace, uintptr_t pc,
+                          uintptr_t* offset) {
+  unw_context_t* context = (unw_context_t*)backtrace->private_data;
+  char buf[512];
+
+  if (unw_get_proc_name_by_ip(unw_local_addr_space, pc, buf, sizeof(buf),
+                              offset, context) >= 0 && buf[0] != '\0') {
+    char* symbol = demangle_symbol_name(buf);
+    if (!symbol) {
+      symbol = strdup(buf);
+    }
+    return symbol;
+  }
+  return NULL;
+}
diff --git a/libbacktrace/unwind_remote.c b/libbacktrace/unwind_remote.c
new file mode 100644
index 0000000..ebbde2e
--- /dev/null
+++ b/libbacktrace/unwind_remote.c
@@ -0,0 +1,151 @@
+/*
+ * 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 <sys/ptrace.h>
+#include <string.h>
+
+#include <cutils/log.h>
+#include <backtrace/backtrace.h>
+
+#include <libunwind.h>
+#include <libunwind-ptrace.h>
+
+#include "common.h"
+#include "demangle.h"
+
+typedef struct {
+  unw_addr_space_t addr_space;
+  struct UPT_info* upt_info;
+} backtrace_private_t;
+
+static bool remote_get_frames(backtrace_t* backtrace) {
+  backtrace_private_t* data = (backtrace_private_t*)backtrace->private_data;
+  unw_cursor_t cursor;
+  int ret = unw_init_remote(&cursor, data->addr_space, data->upt_info);
+  if (ret < 0) {
+    ALOGW("remote_get_frames: unw_init_remote failed %d\n", ret);
+    return false;
+  }
+
+  backtrace_frame_data_t* frame;
+  bool returnValue = true;
+  backtrace->num_frames = 0;
+  uintptr_t map_start;
+  do {
+    frame = &backtrace->frames[backtrace->num_frames];
+    frame->stack_size = 0;
+    frame->map_name = NULL;
+    frame->map_offset = 0;
+    frame->proc_name = NULL;
+    frame->proc_offset = 0;
+
+    ret = unw_get_reg(&cursor, UNW_REG_IP, &frame->pc);
+    if (ret < 0) {
+      ALOGW("remote_get_frames: Failed to read IP %d\n", ret);
+      returnValue = false;
+      break;
+    }
+    ret = unw_get_reg(&cursor, UNW_REG_SP, &frame->sp);
+    if (ret < 0) {
+      ALOGW("remote_get_frames: Failed to read SP %d\n", ret);
+      returnValue = false;
+      break;
+    }
+    if (backtrace->num_frames) {
+      backtrace_frame_data_t* prev = &backtrace->frames[backtrace->num_frames-1];
+      prev->stack_size = frame->sp - prev->sp;
+    }
+
+    frame->proc_name = backtrace_get_proc_name(backtrace, frame->pc, &frame->proc_offset);
+
+    frame->map_name = backtrace_get_map_info(backtrace, frame->pc, &map_start);
+    if (frame->map_name) {
+      frame->map_offset = frame->pc - map_start;
+    }
+
+    backtrace->num_frames++;
+    ret = unw_step (&cursor);
+  } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES);
+
+  return returnValue;
+}
+
+bool remote_get_data(backtrace_t* backtrace) {
+  backtrace_private_t* data = (backtrace_private_t*)malloc(sizeof(backtrace_private_t));
+  if (!data) {
+    ALOGW("remote_get_data: Failed to allocate memory.\n");
+    backtrace_free_data(backtrace);
+    return false;
+  }
+  data->addr_space = NULL;
+  data->upt_info = NULL;
+
+  backtrace->private_data = data;
+  data->addr_space = unw_create_addr_space(&_UPT_accessors, 0);
+  if (!data->addr_space) {
+    ALOGW("remote_get_data: Failed to create unw address space.\n");
+    backtrace_free_data(backtrace);
+    return false;
+  }
+
+  data->upt_info = _UPT_create(backtrace->tid);
+  if (!data->upt_info) {
+    ALOGW("remote_get_data: Failed to create upt info.\n");
+    backtrace_free_data(backtrace);
+    return false;
+  }
+
+  if (!remote_get_frames(backtrace)) {
+    backtrace_free_data(backtrace);
+    return false;
+  }
+
+  return true;
+}
+
+void remote_free_data(backtrace_t* backtrace) {
+  if (backtrace->private_data) {
+    backtrace_private_t* data = (backtrace_private_t*)backtrace->private_data;
+    if (data->upt_info) {
+      _UPT_destroy(data->upt_info);
+      data->upt_info = NULL;
+    }
+    if (data->addr_space) {
+      unw_destroy_addr_space(data->addr_space);
+    }
+
+    free(backtrace->private_data);
+    backtrace->private_data = NULL;
+  }
+}
+
+char* remote_get_proc_name(const backtrace_t* backtrace, uintptr_t pc,
+                           uintptr_t* offset) {
+  backtrace_private_t* data = (backtrace_private_t*)backtrace->private_data;
+  char buf[512];
+
+  if (unw_get_proc_name_by_ip(data->addr_space, pc, buf, sizeof(buf), offset,
+                              data->upt_info) >= 0 && buf[0] != '\0') {
+    char* symbol = demangle_symbol_name(buf);
+    if (!symbol) {
+      symbol = strdup(buf);
+    }
+    return symbol;
+  }
+  return NULL;
+}
diff --git a/libcorkscrew/Android.mk b/libcorkscrew/Android.mk
index d62c2d5..e275317 100644
--- a/libcorkscrew/Android.mk
+++ b/libcorkscrew/Android.mk
@@ -51,7 +51,7 @@
 
 LOCAL_SHARED_LIBRARIES += libdl libcutils liblog libgccdemangle
 
-LOCAL_CFLAGS += -std=gnu99 -Werror
+LOCAL_CFLAGS += -std=gnu99 -Werror -Wno-unused-parameter
 LOCAL_MODULE := libcorkscrew
 LOCAL_MODULE_TAGS := optional
 
@@ -81,7 +81,7 @@
   LOCAL_SHARED_LIBRARIES += libgccdemangle # TODO: is this even needed on Linux?
   LOCAL_LDLIBS += -lrt
 endif
-LOCAL_CFLAGS += -std=gnu99 -Werror
+LOCAL_CFLAGS += -std=gnu99 -Werror -Wno-unused-parameter
 LOCAL_MODULE := libcorkscrew
 LOCAL_MODULE_TAGS := optional
 include $(BUILD_HOST_SHARED_LIBRARY)
diff --git a/libcorkscrew/arch-x86/backtrace-x86.c b/libcorkscrew/arch-x86/backtrace-x86.c
index e133ab6..ef22821 100755
--- a/libcorkscrew/arch-x86/backtrace-x86.c
+++ b/libcorkscrew/arch-x86/backtrace-x86.c
@@ -380,7 +380,7 @@
         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) {
+            if (reg >= DWARF_REGISTERS) {
                 ALOGE("DW_CFA_offset_extended: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
                 return false;
             }
@@ -390,39 +390,39 @@
             break;
         case DW_CFA_restore_extended: // probably we don't have it on x86.
             if (!try_get_uleb128(memory, ptr, &reg, cursor)) return false;
-            dstate->regs[reg].rule = stack->regs[reg].rule;
-            dstate->regs[reg].value = stack->regs[reg].value;
-            if (reg > DWARF_REGISTERS) {
+            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;
-            dstate->regs[reg].rule = 'u';
-            dstate->regs[reg].value = 0;
-            if (reg > DWARF_REGISTERS) {
+            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;
-            dstate->regs[reg].rule = 's';
-            dstate->regs[reg].value = 0;
-            if (reg > DWARF_REGISTERS) {
+            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) {
+            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;
             }
@@ -520,7 +520,7 @@
 
 /* Updaing state based on dwarf state. */
 static bool update_state(const memory_t* memory, unwind_state_t* state,
-                         dwarf_state_t* dstate, cie_info_t* cie_info) {
+                         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. */
@@ -550,7 +550,6 @@
 
 /* Execute CIE and FDE instructions for FDE found with find_fde. */
 static bool execute_fde(const memory_t* memory,
-                        const map_info_t* map_info_list,
                         uintptr_t fde,
                         unwind_state_t* state) {
     uint32_t fde_length = 0;
@@ -753,7 +752,7 @@
         ALOGV("IP: %x, LOC: %x", state->reg[DWARF_EIP], dstate->loc);
     }
 
-    return update_state(memory, state, dstate, cie_info);
+    return update_state(memory, state, dstate);
 }
 
 static ssize_t unwind_backtrace_common(const memory_t* memory,
@@ -805,7 +804,7 @@
 
         uint32_t stack_top = state->reg[DWARF_ESP];
 
-        if (!execute_fde(memory, map_info_list, fde, state)) break;
+        if (!execute_fde(memory, fde, state)) break;
 
         if (frame) {
             frame->stack_top = stack_top;
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 0fd5a57..62f4290 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -115,18 +115,22 @@
         uevent.c
 
 ifeq ($(TARGET_ARCH),arm)
-LOCAL_SRC_FILES += arch-arm/memset32.S
+    LOCAL_SRC_FILES += arch-arm/memset32.S
 else  # !arm
-ifeq ($(TARGET_ARCH_VARIANT),x86-atom)
-LOCAL_CFLAGS += -DHAVE_MEMSET16 -DHAVE_MEMSET32
-LOCAL_SRC_FILES += arch-x86/android_memset16.S arch-x86/android_memset32.S memory.c
-else # !x86-atom
-ifeq ($(TARGET_ARCH),mips)
-LOCAL_SRC_FILES += arch-mips/android_memset.c
-else # !mips
-LOCAL_SRC_FILES += memory.c
-endif # !mips
-endif # !x86-atom
+    ifeq ($(TARGET_ARCH),x86)
+        ifeq ($(ARCH_X86_HAVE_SSE2),true)
+            LOCAL_CFLAGS += -DHAVE_MEMSET16 -DHAVE_MEMSET32 -DUSE_SSE2
+            LOCAL_SRC_FILES += arch-x86/android_memset16.S arch-x86/android_memset32.S memory.c
+        else # !ARCH_X86_HAVE_SSE2
+            LOCAL_SRC_FILES += memory.c
+        endif # !ARCH_X86_HAVE_SSE2
+    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_C_INCLUDES := $(libcutils_c_includes) $(KERNEL_HEADERS)
diff --git a/libcutils/ashmem-dev.c b/libcutils/ashmem-dev.c
index 8b71f87..3089a94 100644
--- a/libcutils/ashmem-dev.c
+++ b/libcutils/ashmem-dev.c
@@ -48,7 +48,7 @@
 		return fd;
 
 	if (name) {
-		char buf[ASHMEM_NAME_LEN];
+		char buf[ASHMEM_NAME_LEN] = {0};
 
 		strlcpy(buf, name, sizeof(buf));
 		ret = ioctl(fd, ASHMEM_SET_NAME, buf);
diff --git a/libsparse/output_file.c b/libsparse/output_file.c
index 5014e4a..2428022 100644
--- a/libsparse/output_file.c
+++ b/libsparse/output_file.c
@@ -46,15 +46,6 @@
 #define off64_t off_t
 #endif
 
-#ifdef __BIONIC__
-extern void*  __mmap2(void *, size_t, int, int, int, off_t);
-static inline void *mmap64(void *addr, size_t length, int prot, int flags,
-        int fd, off64_t offset)
-{
-    return __mmap2(addr, length, prot, flags, fd, offset >> 12);
-}
-#endif
-
 #define min(a, b) \
 	({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; })
 
diff --git a/mkbootimg/bootimg.h b/mkbootimg/bootimg.h
index 242ab35..9171d85 100644
--- a/mkbootimg/bootimg.h
+++ b/mkbootimg/bootimg.h
@@ -24,6 +24,7 @@
 #define BOOT_MAGIC_SIZE 8
 #define BOOT_NAME_SIZE 16
 #define BOOT_ARGS_SIZE 512
+#define BOOT_EXTRA_ARGS_SIZE 1024
 
 struct boot_img_hdr
 {
@@ -43,10 +44,14 @@
     unsigned unused[2];    /* future expansion: should be 0 */
 
     unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
-    
+
     unsigned char cmdline[BOOT_ARGS_SIZE];
 
     unsigned id[8]; /* timestamp / checksum / sha1 / etc */
+
+    /* Supplemental command line data; kept here to maintain
+     * binary compatibility with older versions of mkbootimg */
+    unsigned char extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
 };
 
 /*
diff --git a/mkbootimg/mkbootimg.c b/mkbootimg/mkbootimg.c
index 34a879b..d598f03 100644
--- a/mkbootimg/mkbootimg.c
+++ b/mkbootimg/mkbootimg.c
@@ -114,6 +114,7 @@
     unsigned ramdisk_offset = 0x01000000;
     unsigned second_offset  = 0x00f00000;
     unsigned tags_offset    = 0x00000100;
+    size_t cmdlen;
 
     argc--;
     argv++;
@@ -192,11 +193,19 @@
 
     memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
 
-    if(strlen(cmdline) > (BOOT_ARGS_SIZE - 1)) {
+    cmdlen = strlen(cmdline);
+    if(cmdlen > (BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE - 2)) {
         fprintf(stderr,"error: kernel commandline too large\n");
         return 1;
     }
-    strcpy((char*)hdr.cmdline, cmdline);
+    /* Even if we need to use the supplemental field, ensure we
+     * are still NULL-terminated */
+    strncpy((char *)hdr.cmdline, cmdline, BOOT_ARGS_SIZE - 1);
+    hdr.cmdline[BOOT_ARGS_SIZE - 1] = '\0';
+    if (cmdlen >= (BOOT_ARGS_SIZE - 1)) {
+        cmdline += (BOOT_ARGS_SIZE - 1);
+        strncpy((char *)hdr.extra_cmdline, cmdline, BOOT_EXTRA_ARGS_SIZE);
+    }
 
     kernel_data = load_file(kernel_fn, &hdr.kernel_size);
     if(kernel_data == 0) {
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 8150a73..b13cf62 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -349,7 +349,6 @@
     chown root radio /proc/cmdline
 
 # Set these so we can remotely update SELinux policy
-    chown system system /sys/fs/selinux/load
     chown system system /sys/fs/selinux/enforce
 
 # Define TCP buffer sizes for various networks
@@ -419,10 +418,6 @@
     critical
     seclabel u:r:healthd:s0
 
-on property:selinux.reload_policy=1
-    restart ueventd
-    restart installd
-
 service console /system/bin/sh
     class core
     console