merge in ics-release history after reset to master
diff --git a/charger/charger.c b/charger/charger.c
index d3b414d..03280bf 100644
--- a/charger/charger.c
+++ b/charger/charger.c
@@ -224,7 +224,7 @@
 
         yoink = ptr[cnt];
         ptr[cnt] = '\0';
-        KLOG_INFO("", "%s", ptr);
+        klog_write(6, "<6>%s", ptr);
         ptr[cnt] = yoink;
 
         len -= cnt;
@@ -745,30 +745,44 @@
     }
 }
 
-static void update_input_state(struct charger *charger,
-                               struct input_event *ev,
-                               int64_t now)
+static int set_key_callback(int code, int value, void *data)
 {
-    int down = !!ev->value;
+    struct charger *charger = data;
+    int64_t now = curr_time_ms();
+    int down = !!value;
 
-    if (ev->type != EV_KEY || ev->code > KEY_MAX)
-        return;
+    if (code > KEY_MAX)
+        return -1;
+
+    /* ignore events that don't modify our state */
+    if (charger->keys[code].down == down)
+        return 0;
 
     /* only record the down even timestamp, as the amount
      * of time the key spent not being pressed is not useful */
     if (down)
-        charger->keys[ev->code].timestamp = now;
-    charger->keys[ev->code].down = down;
-    charger->keys[ev->code].pending = true;
+        charger->keys[code].timestamp = now;
+    charger->keys[code].down = down;
+    charger->keys[code].pending = true;
     if (down) {
-        LOGV("[%lld] key[%d] down\n", now, ev->code);
+        LOGV("[%lld] key[%d] down\n", now, code);
     } else {
-        int64_t duration = now - charger->keys[ev->code].timestamp;
+        int64_t duration = now - charger->keys[code].timestamp;
         int64_t secs = duration / 1000;
         int64_t msecs = duration - secs * 1000;
         LOGV("[%lld] key[%d] up (was down for %lld.%lldsec)\n", now,
-            ev->code, secs, msecs);
+            code, secs, msecs);
     }
+
+    return 0;
+}
+
+static void update_input_state(struct charger *charger,
+                               struct input_event *ev)
+{
+    if (ev->type != EV_KEY)
+        return;
+    set_key_callback(ev->code, ev->value, charger);
 }
 
 static void set_next_key_check(struct charger *charger,
@@ -876,7 +890,7 @@
     ret = ev_get_input(fd, revents, &ev);
     if (ret)
         return -1;
-    update_input_state(charger, &ev, curr_time_ms());
+    update_input_state(charger, &ev);
     return 0;
 }
 
@@ -949,6 +963,8 @@
         }
     }
 
+    ev_sync_key_state(set_key_callback, charger);
+
     gr_fb_blank(true);
 
     charger->next_screen_transition = now - 1;
diff --git a/debuggerd/arm/machine.c b/debuggerd/arm/machine.c
index 88bf054..58a7839 100644
--- a/debuggerd/arm/machine.c
+++ b/debuggerd/arm/machine.c
@@ -50,6 +50,74 @@
                                         int *frame0_pc_sane,
                                         bool at_fault);
 
+/*
+ * If this isn't clearly a null pointer dereference, dump the
+ * /proc/maps entries near the fault address.
+ */
+static void show_nearby_maps(int tfd, int pid, mapinfo *map)
+{
+    siginfo_t si;
+
+    memset(&si, 0, sizeof(si));
+    if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si)) {
+        _LOG(tfd, false, "cannot get siginfo: %s\n", strerror(errno));
+        return;
+    }
+    if (!signal_has_address(si.si_signo))
+        return;
+
+    uintptr_t addr = (uintptr_t) si.si_addr;
+    addr &= ~0xfff;     /* round to 4K page boundary */
+    if (addr == 0)      /* null-pointer deref */
+        return;
+
+    _LOG(tfd, false, "\nmemory map around addr %08x:\n", si.si_addr);
+
+    /*
+     * 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.
+     */
+    bool found = false;
+    mapinfo *next = NULL;
+    mapinfo *prev = NULL;
+    while (map != NULL) {
+        if (addr >= map->start && addr < map->end) {
+            found = true;
+            next = map->next;
+            break;
+        } else if (addr >= map->end) {
+            /* map would be between "prev" and this entry */
+            next = map;
+            map = NULL;
+            break;
+        }
+
+        prev = map;
+        map = map->next;
+    }
+
+    /*
+     * Show "next" then "match" then "prev" so that the addresses appear in
+     * ascending order (like /proc/pid/maps).
+     */
+    if (next != NULL) {
+        _LOG(tfd, false, "%08x-%08x %s\n", next->start, next->end, next->name);
+    } else {
+        _LOG(tfd, false, "(no map below)\n");
+    }
+    if (map != NULL) {
+        _LOG(tfd, false, "%08x-%08x %s\n", map->start, map->end, map->name);
+    } else {
+        _LOG(tfd, false, "(no map for address)\n");
+    }
+    if (prev != NULL) {
+        _LOG(tfd, false, "%08x-%08x %s\n", prev->start, prev->end, prev->name);
+    } else {
+        _LOG(tfd, false, "(no map above)\n");
+    }
+}
+
+
 void dump_stack_and_code(int tfd, int pid, mapinfo *map,
                          int unwind_depth, unsigned int sp_list[],
                          bool at_fault)
@@ -123,6 +191,8 @@
         }
     }
 
+    show_nearby_maps(tfd, pid, map);
+
     p = sp - 64;
     if (p > sp)
         p = 0;
diff --git a/debuggerd/debuggerd.c b/debuggerd/debuggerd.c
index d03c214..91d9dda 100644
--- a/debuggerd/debuggerd.c
+++ b/debuggerd/debuggerd.c
@@ -31,6 +31,7 @@
 
 #include <cutils/sockets.h>
 #include <cutils/logd.h>
+#include <cutils/logger.h>
 #include <cutils/properties.h>
 
 #include <linux/input.h>
@@ -70,14 +71,17 @@
     mapinfo *mi;
     int len = strlen(line);
 
-    if(len < 1) return 0;
+    if (len < 1) return 0;      /* not expected */
     line[--len] = 0;
 
-    if(len < 50) return 0;
-    if(line[20] != 'x') return 0;
+    if (len < 50) {
+        mi = malloc(sizeof(mapinfo) + 1);
+    } else {
+        mi = malloc(sizeof(mapinfo) + (len - 47));
+    }
+    if (mi == 0) return 0;
 
-    mi = malloc(sizeof(mapinfo) + (len - 47));
-    if(mi == 0) return 0;
+    mi->isExecutable = (line[20] == 'x');
 
     mi->start = strtoul(line, 0, 16);
     mi->end = strtoul(line + 9, 0, 16);
@@ -87,7 +91,11 @@
     mi->exidx_start = mi->exidx_end = 0;
     mi->symbols = 0;
     mi->next = 0;
-    strcpy(mi->name, line + 49);
+    if (len < 50) {
+        mi->name[0] = '\0';
+    } else {
+        strcpy(mi->name, line + 49);
+    }
 
     return mi;
 }
@@ -165,11 +173,14 @@
     memset(&si, 0, sizeof(si));
     if(ptrace(PTRACE_GETSIGINFO, pid, 0, &si)){
         _LOG(tfd, false, "cannot get siginfo: %s\n", strerror(errno));
-    } else {
+    } else if (signal_has_address(sig)) {
         _LOG(tfd, false, "signal %d (%s), code %d (%s), fault addr %08x\n",
              sig, get_signame(sig),
              si.si_code, get_sigcode(sig, si.si_code),
              si.si_addr);
+    } else {
+        _LOG(tfd, false, "signal %d (%s), code %d (%s), fault addr --------\n",
+             sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code));
     }
 }
 
@@ -199,6 +210,9 @@
 {
     mapinfo *mi;
     for (mi = milist; mi != NULL; mi = mi->next) {
+        if (!mi->isExecutable)
+            continue;
+
         Elf32_Ehdr ehdr;
 
         memset(&ehdr, 0, sizeof(Elf32_Ehdr));
@@ -400,6 +414,101 @@
     return need_cleanup != 0;
 }
 
+/*
+ * 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.
+ */
+static void dump_log_file(int tfd, unsigned pid, const char* filename)
+{
+    int logfd = open(filename, O_RDONLY | O_NONBLOCK);
+    if (logfd < 0) {
+        XLOG("Unable to open %s: %s\n", filename, strerror(errno));
+        return;
+    }
+    _LOG(tfd, true, "--------- log %s\n", filename);
+
+    union {
+        unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
+        struct logger_entry entry;
+    } log_entry;
+
+    while (true) {
+        ssize_t actual = read(logfd, log_entry.buf, LOGGER_ENTRY_MAX_LEN);
+        if (actual < 0) {
+            if (errno == EINTR) {
+                /* interrupted by signal, retry */
+                continue;
+            } else if (errno == EAGAIN) {
+                /* non-blocking EOF; we're done */
+                break;
+            } else {
+                _LOG(tfd, true, "Error while reading log: %s\n",
+                    strerror(errno));
+                break;
+            }
+        } else if (actual == 0) {
+            _LOG(tfd, true, "Got zero bytes while reading log: %s\n",
+                strerror(errno));
+            break;
+        }
+
+        /*
+         * NOTE: if you XLOG 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;
+
+        if (entry->pid != (int32_t) pid) {
+            /* wrong pid, ignore */
+            continue;
+        }
+
+        /*
+         * Msg format is: <priority:1><tag:N>\0<message:N>\0
+         *
+         * We want to display it in the same format as "logcat -v threadtime"
+         * (although in this case the pid is redundant).
+         *
+         * TODO: scan for line breaks ('\n') and display each text line
+         * on a separate line, prefixed with the header, like logcat does.
+         */
+        static const char* kPrioChars = "!.VDIWEFS";
+        unsigned char prio = entry->msg[0];
+        const char* tag = entry->msg + 1;
+        const char* msg = tag + strlen(tag) + 1;
+
+        log_entry.entry.msg[entry->len] = '\0';
+
+        char timeBuf[32];
+        time_t sec = (time_t) entry->sec;
+        struct tm tmBuf;
+        struct tm* ptm;
+        ptm = localtime_r(&sec, &tmBuf);
+        strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
+
+        _LOG(tfd, true, "%s.%03ld %5d %5d %c %-8s: %s\n",
+            timeBuf, entry->nsec / 1000000,
+            entry->pid, entry->tid,
+            (prio < strlen(kPrioChars) ? kPrioChars[prio] : '?'),
+            tag, msg);
+    }
+
+    close(logfd);
+}
+
+/*
+ * 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(int tfd, unsigned pid)
+{
+    dump_log_file(tfd, pid, "/dev/log/system");
+    dump_log_file(tfd, pid, "/dev/log/main");
+}
+
 /* Return true if some thread is not detached cleanly */
 static bool engrave_tombstone(unsigned pid, unsigned tid, int debug_uid,
                               int signal)
@@ -424,6 +533,13 @@
         need_cleanup = dump_sibling_thread_report(fd, pid, tid);
     }
 
+    /* don't copy log to tombstone unless this is a dev device */
+    char value[PROPERTY_VALUE_MAX];
+    property_get("ro.debuggable", value, "0");
+    if (value[0] == '1') {
+        dump_logs(fd, pid);
+    }
+
     close(fd);
     return need_cleanup;
 }
diff --git a/debuggerd/utility.c b/debuggerd/utility.c
index 2afdb46..409209c 100644
--- a/debuggerd/utility.c
+++ b/debuggerd/utility.c
@@ -17,6 +17,7 @@
 
 #include <sys/ptrace.h>
 #include <sys/exec_elf.h>
+#include <signal.h>
 #include <assert.h>
 #include <string.h>
 #include <errno.h>
@@ -82,3 +83,20 @@
     }
     return NULL;
 }
+
+/*
+ * Returns true if the specified signal has an associated address (i.e. it
+ * sets siginfo_t.si_addr).
+ */
+bool signal_has_address(int sig)
+{
+    switch (sig) {
+        case SIGILL:
+        case SIGFPE:
+        case SIGSEGV:
+        case SIGBUS:
+            return true;
+        default:
+            return false;
+    }
+}
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index 45e2067..4a935d2 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -36,6 +36,7 @@
     unsigned exidx_start;
     unsigned exidx_end;
     struct symbol_table *symbols;
+    bool isExecutable;
     char name[];
 } mapinfo;
 
@@ -56,6 +57,9 @@
 /* Log information onto the tombstone */
 extern void _LOG(int tfd, bool in_tombstone_only, const char *fmt, ...);
 
+/* Determine whether si_addr is valid for this signal */
+bool signal_has_address(int sig);
+
 #define LOG(fmt...) _LOG(-1, 0, fmt)
 
 /* Set to 1 for normal debug traces */