Merge "Link with libgccdemangle.so for name demangling."
diff --git a/adb/adb.c b/adb/adb.c
index a91004c..e35c334 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -907,9 +907,11 @@
         ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
         ** AID_SDCARD_RW to allow writing to the SD card
         ** AID_MOUNT to allow unmounting the SD card before rebooting
+        ** 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_RW, AID_MOUNT };
+                           AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_RW, AID_MOUNT,
+                           AID_NET_BW_STATS };
         if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
             exit(1);
         }
diff --git a/debuggerd/debuggerd.c b/debuggerd/debuggerd.c
index 20ffc13..0f05bfd 100644
--- a/debuggerd/debuggerd.c
+++ b/debuggerd/debuggerd.c
@@ -395,13 +395,13 @@
  * find_and_open_tombstone - find an available tombstone slot, if any, of the
  * form tombstone_XX where XX is 00 to MAX_TOMBSTONES-1, inclusive. If no
  * file is available, we reuse the least-recently-modified file.
+ *
+ * Returns the path of the tombstone file, allocated using malloc().  Caller must free() it.
  */
-static int find_and_open_tombstone(void)
+static char* find_and_open_tombstone(int* fd)
 {
     unsigned long mtime = ULONG_MAX;
     struct stat sb;
-    char path[128];
-    int fd, i, oldest = 0;
 
     /*
      * XXX: Our stat.st_mtime isn't time_t. If it changes, as it probably ought
@@ -413,7 +413,9 @@
      * In a single wolf-like pass, find an available slot and, in case none
      * exist, find and record the least-recently-modified file.
      */
-    for (i = 0; i < MAX_TOMBSTONES; i++) {
+    char path[128];
+    int oldest = 0;
+    for (int i = 0; i < MAX_TOMBSTONES; i++) {
         snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", i);
 
         if (!stat(path, &sb)) {
@@ -426,38 +428,43 @@
         if (errno != ENOENT)
             continue;
 
-        fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0600);
-        if (fd < 0)
+        *fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0600);
+        if (*fd < 0)
             continue;	/* raced ? */
 
-        fchown(fd, AID_SYSTEM, AID_SYSTEM);
-        return fd;
+        fchown(*fd, AID_SYSTEM, AID_SYSTEM);
+        return strdup(path);
     }
 
     /* we didn't find an available file, so we clobber the oldest one */
     snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", oldest);
-    fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
-    fchown(fd, AID_SYSTEM, AID_SYSTEM);
-
-    return fd;
+    *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));
+        return NULL;
+    }
+    fchown(*fd, AID_SYSTEM, AID_SYSTEM);
+    return strdup(path);
 }
 
 /* Return true if some thread is not detached cleanly */
-static bool engrave_tombstone(pid_t pid, pid_t tid, int signal,
-        bool dump_sibling_threads)
+static char* engrave_tombstone(pid_t pid, pid_t tid, int signal, bool dump_sibling_threads,
+        bool* detach_failed)
 {
     mkdir(TOMBSTONE_DIR, 0755);
     chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM);
 
-    int fd = find_and_open_tombstone();
-    if (fd < 0) {
-        return false;
+    int fd;
+    char* path = find_and_open_tombstone(&fd);
+    if (!path) {
+        *detach_failed = false;
+        return NULL;
     }
 
-    bool detach_failed = dump_crash(fd, pid, tid, signal, dump_sibling_threads);
+    *detach_failed = dump_crash(fd, pid, tid, signal, dump_sibling_threads);
 
     close(fd);
-    return detach_failed;
+    return path;
 }
 
 static int
@@ -734,8 +741,12 @@
             if (TEMP_FAILURE_RETRY(write(fd, &response, 1)) != 1) {
                 LOG("failed responding to client: %s\n", strerror(errno));
             } else {
-                close(fd);
-                fd = -1;
+                char* tombstone_path = NULL;
+
+                if (request.type != REQUEST_TYPE_DUMP) {
+                    close(fd);
+                    fd = -1;
+                }
 
                 int total_sleep_time_usec = 0;
                 for (;;) {
@@ -748,8 +759,8 @@
                     case SIGSTOP:
                         if (request.type == REQUEST_TYPE_DUMP) {
                             XLOG("stopped -- dumping\n");
-                            detach_failed = engrave_tombstone(request.pid, request.tid,
-                                    signal, true);
+                            tombstone_path = engrave_tombstone(request.pid, request.tid,
+                                    signal, true, &detach_failed);
                         } else {
                             XLOG("stopped -- continuing\n");
                             status = ptrace(PTRACE_CONT, request.tid, 0, 0);
@@ -769,8 +780,8 @@
                         XLOG("stopped -- fatal signal\n");
                         /* don't dump sibling threads when attaching to GDB because it
                          * makes the process less reliable, apparently... */
-                        detach_failed = engrave_tombstone(request.pid, request.tid,
-                                signal, !attach_gdb);
+                        tombstone_path = engrave_tombstone(request.pid, request.tid,
+                                signal, !attach_gdb, &detach_failed);
                         break;
                     }
 
@@ -781,6 +792,15 @@
                     }
                     break;
                 }
+
+                if (request.type == REQUEST_TYPE_DUMP) {
+                    if (tombstone_path) {
+                        write(fd, tombstone_path, strlen(tombstone_path));
+                    }
+                    close(fd);
+                    fd = -1;
+                }
+                free(tombstone_path);
             }
 
             XLOG("detaching\n");
@@ -900,7 +920,17 @@
     if (read(fd, &request, 1) != 1) {
         /* did not get expected reply, debuggerd must have closed the socket */
         fputs("Error sending request.  Did not receive reply from debuggerd.\n", stderr);
+    } else {
+        char tombstone_path[PATH_MAX];
+        ssize_t n = read(fd, &tombstone_path, sizeof(tombstone_path) - 1);
+        if (n <= 0) {
+            fputs("Error dumping process.  Check log for details.\n", stderr);
+        } else {
+            tombstone_path[n] = '\0';
+            fprintf(stderr, "Tombstone written to: %s\n", tombstone_path);
+        }
     }
+
     close(fd);
     return 0;
 }
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
index 3ab5d1b..d18931b 100644
--- a/libnetutils/dhcp_utils.c
+++ b/libnetutils/dhcp_utils.c
@@ -145,6 +145,11 @@
 /*
  * Start the dhcp client daemon, and wait for it to finish
  * configuring the interface.
+ *
+ * The device init.rc file needs a corresponding entry for this work.
+ *
+ * Example:
+ * service dhcpcd_<interface> /system/bin/dhcpcd -ABKL
  */
 int dhcp_do_request(const char *interface,
                     char *ipaddr,
@@ -287,13 +292,16 @@
 }
 
 /**
- * Run WiMAX dhcp renew service.
- * "wimax_renew" service shoud be included in init.rc.
+ * The device init.rc file needs a corresponding entry.
+ *
+ * Example:
+ * service iprenew_<interface> /system/bin/dhcpcd -n
+ *
  */
 int dhcp_do_request_renew(const char *interface,
                     in_addr_t *ipaddr,
                     in_addr_t *gateway,
-                    in_addr_t *mask,
+                    uint32_t *prefixLength,
                     in_addr_t *dns1,
                     in_addr_t *dns2,
                     in_addr_t *server,
@@ -333,7 +341,7 @@
         return -1;
     }
     if (strcmp(prop_value, "ok") == 0) {
-        fill_ip_info(interface, ipaddr, gateway, mask, dns1, dns2, server, lease);
+        fill_ip_info(interface, ipaddr, gateway, prefixLength, dns1, dns2, server, lease);
         return 0;
     } else {
         snprintf(errmsg, sizeof(errmsg), "DHCP Renew result was %s", prop_value);
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 235533f..f44d89a 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -69,6 +69,7 @@
     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
 
 # Create cgroup mount points for process groups
     mkdir /dev/cpuctl