Reconcile with ics-factoryrom-2-release

Change-Id: Ibfe7c2c1d309f7caae0be71ae631b69830f4e624
diff --git a/charger/charger.c b/charger/charger.c
index 03280bf..abf5517 100644
--- a/charger/charger.c
+++ b/charger/charger.c
@@ -87,6 +87,7 @@
     const char *name;
     int disp_time;
     int min_capacity;
+    bool level_only;
 
     gr_surface surface;
 };
@@ -157,6 +158,7 @@
         .name = "charger/battery_4",
         .disp_time = 750,
         .min_capacity = 80,
+        .level_only = true,
     },
     {
         .name = "charger/battery_5",
@@ -735,7 +737,14 @@
      * if necessary, advance cycle cntr, and reset frame cntr
      */
     batt_anim->cur_frame++;
-    if (batt_anim->cur_frame == batt_anim->num_frames) {
+
+    /* if the frame is used for level-only, that is only show it when it's
+     * the current level, skip it during the animation.
+     */
+    while (batt_anim->cur_frame < batt_anim->num_frames &&
+           batt_anim->frames[batt_anim->cur_frame].level_only)
+        batt_anim->cur_frame++;
+    if (batt_anim->cur_frame >= batt_anim->num_frames) {
         batt_anim->cur_cycle++;
         batt_anim->cur_frame = 0;
 
diff --git a/debuggerd/arm/machine.c b/debuggerd/arm/machine.c
index 88bf054..5055444 100644
--- a/debuggerd/arm/machine.c
+++ b/debuggerd/arm/machine.c
@@ -36,6 +36,9 @@
 
 #include "utility.h"
 
+/* enable to dump memory pointed to by every register */
+#define DUMP_MEM_FOR_ALL_REGS 1
+
 #ifdef WITH_VFP
 #ifdef WITH_VFP_D32
 #define NUM_VFP_REGS 32
@@ -50,79 +53,200 @@
                                         int *frame0_pc_sane,
                                         bool at_fault);
 
-void dump_stack_and_code(int tfd, int pid, mapinfo *map,
-                         int unwind_depth, unsigned int sp_list[],
-                         bool at_fault)
+/*
+ * If this isn't clearly a null pointer dereference, dump the
+ * /proc/maps entries near the fault address.
+ *
+ * This only makes sense to do on the thread that crashed.
+ */
+static void show_nearby_maps(int tfd, int pid, mapinfo *map)
 {
-    unsigned int sp, pc, lr, p, end, data;
-    struct pt_regs r;
-    int sp_depth;
-    bool only_in_tombstone = !at_fault;
-    char code_buffer[80];
+    siginfo_t si;
 
-    if(ptrace(PTRACE_GETREGS, pid, 0, &r)) return;
-    sp = r.ARM_sp;
-    pc = r.ARM_pc;
-    lr = r.ARM_lr;
+    memset(&si, 0, sizeof(si));
+    if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si)) {
+        _LOG(tfd, false, "cannot get siginfo for %d: %s\n",
+            pid, strerror(errno));
+        return;
+    }
+    if (!signal_has_address(si.si_signo))
+        return;
 
-    _LOG(tfd, only_in_tombstone, "\ncode around pc:\n");
+    uintptr_t addr = (uintptr_t) si.si_addr;
+    addr &= ~0xfff;     /* round to 4K page boundary */
+    if (addr == 0)      /* null-pointer deref */
+        return;
 
-    p = pc & ~3;
+    _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");
+    }
+}
+
+/*
+ * Dumps a few bytes of memory, starting a bit before and ending a bit
+ * after the specified address.
+ */
+static void dump_memory(int tfd, int pid, uintptr_t addr,
+    bool only_in_tombstone)
+{
+    char code_buffer[64];       /* actual 8+1+((8+1)*4) + 1 == 45 */
+    char ascii_buffer[32];      /* actual 16 + 1 == 17 */
+    uintptr_t p, end;
+
+    p = addr & ~3;
     p -= 32;
-    if (p > pc)
+    if (p > addr) {
+        /* catch underflow */
         p = 0;
+    }
     end = p + 80;
-    /* 'end - p' has to be multiples of 16 */
+    /* catch overflow; 'end - p' has to be multiples of 16 */
     while (end < p)
         end -= 16;
 
     /* Dump the code around PC as:
-     *  addr       contents
-     *  00008d34   fffffcd0 4c0eb530 b0934a0e 1c05447c
-     *  00008d44   f7ff18a0 490ced94 68035860 d0012b00
+     *  addr     contents                             ascii
+     *  00008d34 ef000000 e8bd0090 e1b00000 512fff1e  ............../Q
+     *  00008d44 ea00b1f9 e92d0090 e3a070fc ef000000  ......-..p......
      */
-    while (p <  end) {
-        int i;
+    while (p < end) {
+        char* asc_out = ascii_buffer;
 
         sprintf(code_buffer, "%08x ", p);
+
+        int i;
         for (i = 0; i < 4; i++) {
-            data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
-            sprintf(code_buffer + strlen(code_buffer), "%08x ", data);
+            /*
+             * If we see (data == -1 && errno != 0), we know that the ptrace
+             * call failed, probably because we're dumping memory in an
+             * unmapped or inaccessible page.  I don't know if there's
+             * value in making that explicit in the output -- it likely
+             * just complicates parsing and clarifies nothing for the
+             * enlightened reader.
+             */
+            long data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
+            sprintf(code_buffer + strlen(code_buffer), "%08lx ", data);
+
+            int j;
+            for (j = 0; j < 4; j++) {
+                /*
+                 * Our isprint() allows high-ASCII characters that display
+                 * differently (often badly) in different viewers, so we
+                 * just use a simpler test.
+                 */
+                char val = (data >> (j*8)) & 0xff;
+                if (val >= 0x20 && val < 0x7f) {
+                    *asc_out++ = val;
+                } else {
+                    *asc_out++ = '.';
+                }
+            }
             p += 4;
         }
-        _LOG(tfd, only_in_tombstone, "%s\n", code_buffer);
+        *asc_out = '\0';
+        _LOG(tfd, only_in_tombstone, "%s %s\n", code_buffer, ascii_buffer);
     }
 
-    if (lr != pc) {
-        _LOG(tfd, only_in_tombstone, "\ncode around lr:\n");
+}
 
-        p = lr & ~3;
-        p -= 32;
-        if (p > lr)
-            p = 0;
-        end = p + 80;
-        /* 'end - p' has to be multiples of 16 */
-        while (end < p)
-            end -= 16;
+void dump_stack_and_code(int tfd, int pid, mapinfo *map,
+                         int unwind_depth, unsigned int sp_list[],
+                         bool at_fault)
+{
+    struct pt_regs r;
+    int sp_depth;
+    bool only_in_tombstone = !at_fault;
 
-        /* Dump the code around LR as:
-         *  addr       contents
-         *  00008d34   fffffcd0 4c0eb530 b0934a0e 1c05447c
-         *  00008d44   f7ff18a0 490ced94 68035860 d0012b00
+    if(ptrace(PTRACE_GETREGS, pid, 0, &r)) return;
+
+    if (DUMP_MEM_FOR_ALL_REGS && at_fault) {
+        /*
+         * If configured to do so, dump memory around *all* registers
+         * for the crashing thread.
+         *
+         * TODO: remove duplicates.
          */
-        while (p < end) {
-            int i;
+        static const char REG_NAMES[] = "R0R1R2R3R4R5R6R7R8R9SLFPIPSPLRPC";
 
-            sprintf(code_buffer, "%08x ", p);
-            for (i = 0; i < 4; i++) {
-                data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
-                sprintf(code_buffer + strlen(code_buffer), "%08x ", data);
-                p += 4;
+        int reg;
+        for (reg = 0; reg < 16; reg++) {
+            /* this may not be a valid way to access, but it'll do for now */
+            uintptr_t addr = r.uregs[reg];
+
+            /*
+             * Don't bother if it looks like a small int or ~= null, or if
+             * it's in the kernel area.
+             */
+            if (addr < 4096 || addr >= 0xc0000000) {
+                continue;
             }
-            _LOG(tfd, only_in_tombstone, "%s\n", code_buffer);
+
+            _LOG(tfd, only_in_tombstone, "\nmem near %.2s:\n",
+                &REG_NAMES[reg*2]);
+            dump_memory(tfd, pid, addr, false);
+        }
+    } else {
+        unsigned int pc, lr;
+        pc = r.ARM_pc;
+        lr = r.ARM_lr;
+
+        _LOG(tfd, only_in_tombstone, "\ncode around pc:\n");
+        dump_memory(tfd, pid, (uintptr_t) pc, only_in_tombstone);
+
+        if (lr != pc) {
+            _LOG(tfd, only_in_tombstone, "\ncode around lr:\n");
+            dump_memory(tfd, pid, (uintptr_t) lr, only_in_tombstone);
         }
     }
 
+    if (at_fault) {
+        show_nearby_maps(tfd, pid, map);
+    }
+
+    unsigned int p, end;
+    unsigned int sp = r.ARM_sp;
+
     p = sp - 64;
     if (p > sp)
         p = 0;
@@ -157,7 +281,7 @@
     while (p <= end) {
          char *prompt;
          char level[16];
-         data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
+         long data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
          if (p == sp_list[sp_depth]) {
              sprintf(level, "#%02d", sp_depth++);
              prompt = level;
@@ -182,7 +306,7 @@
         end = ~7;
 
     while (p <= end) {
-         data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
+         long data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
          _LOG(tfd, (sp_depth > 2) || only_in_tombstone,
               "    %08x  %08x  %s\n", p, data,
               map_to_name(map, data, ""));
diff --git a/debuggerd/debuggerd.c b/debuggerd/debuggerd.c
index d03c214..2acf26d 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>
@@ -42,6 +43,9 @@
 
 #define ANDROID_LOG_INFO 4
 
+void _LOG(int tfd, bool in_tombstone_only, const char *fmt, ...)
+    __attribute__ ((format(printf, 3, 4)));
+
 /* Log information onto the tombstone */
 void _LOG(int tfd, bool in_tombstone_only, const char *fmt, ...)
 {
@@ -59,6 +63,7 @@
 
     if (!in_tombstone_only)
         __android_log_vprint(ANDROID_LOG_INFO, "DEBUG", fmt, ap);
+    va_end(ap);
 }
 
 // 6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /system/lib/libcomposer.so
@@ -70,14 +75,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 +95,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 +177,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);
+             (uintptr_t) 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 +214,9 @@
 {
     mapinfo *mi;
     for (mi = milist; mi != NULL; mi = mi->next) {
+        if (!mi->isExecutable)
+            continue;
+
         Elf32_Ehdr ehdr;
 
         memset(&ehdr, 0, sizeof(Elf32_Ehdr));
@@ -394,12 +412,161 @@
             continue;
 
         dump_crash_report(tfd, pid, new_tid, false);
-        need_cleanup |= ptrace(PTRACE_DETACH, new_tid, 0, 0);
+
+        if (ptrace(PTRACE_DETACH, new_tid, 0, 0) != 0) {
+            XLOG("detach of tid %d failed: %s\n", new_tid, strerror(errno));
+            need_cleanup = 1;
+        }
     }
     closedir(d);
+
     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.
+ *
+ * If "tailOnly" is set, we only print the last few lines.
+ */
+static void dump_log_file(int tfd, unsigned pid, const char* filename,
+    bool tailOnly)
+{
+    bool first = true;
+
+    /* circular buffer, for "tailOnly" mode */
+    const int kShortLogMaxLines = 5;
+    const int kShortLogLineLen = 256;
+    char shortLog[kShortLogMaxLines][kShortLogLineLen];
+    int shortLogCount = 0;
+    int shortLogNext = 0;
+
+    int logfd = open(filename, O_RDONLY | O_NONBLOCK);
+    if (logfd < 0) {
+        XLOG("Unable to open %s: %s\n", filename, strerror(errno));
+        return;
+    }
+
+    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;
+        }
+
+        if (first) {
+            _LOG(tfd, true, "--------- %slog %s\n",
+                tailOnly ? "tail end of " : "", filename);
+            first = false;
+        }
+
+        /*
+         * 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];
+        char* tag = entry->msg + 1;
+        char* msg = tag + strlen(tag) + 1;
+
+        /* consume any trailing newlines */
+        char* eatnl = msg + strlen(msg) - 1;
+        while (eatnl >= msg && *eatnl == '\n') {
+            *eatnl-- = '\0';
+        }
+
+        char prioChar = (prio < strlen(kPrioChars) ? kPrioChars[prio] : '?');
+
+        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);
+
+        if (tailOnly) {
+            snprintf(shortLog[shortLogNext], kShortLogLineLen,
+                "%s.%03d %5d %5d %c %-8s: %s",
+                timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
+                prioChar, tag, msg);
+            shortLogNext = (shortLogNext + 1) % kShortLogMaxLines;
+            shortLogCount++;
+        } else {
+            _LOG(tfd, true, "%s.%03d %5d %5d %c %-8s: %s\n",
+                timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
+                prioChar, tag, msg);
+        }
+    }
+
+    if (tailOnly) {
+        int i;
+
+        /*
+         * If we filled the buffer, we want to start at "next", which has
+         * the oldest entry.  If we didn't, we want to start at zero.
+         */
+        if (shortLogCount < kShortLogMaxLines) {
+            shortLogNext = 0;
+        } else {
+            shortLogCount = kShortLogMaxLines;  /* cap at window size */
+        }
+
+        for (i = 0; i < shortLogCount; i++) {
+            _LOG(tfd, true, "%s\n", shortLog[shortLogNext]);
+            shortLogNext = (shortLogNext + 1) % kShortLogMaxLines;
+        }
+    }
+
+    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, bool tailOnly)
+{
+    dump_log_file(tfd, pid, "/dev/log/system", tailOnly);
+    dump_log_file(tfd, pid, "/dev/log/main", tailOnly);
+}
+
 /* Return true if some thread is not detached cleanly */
 static bool engrave_tombstone(unsigned pid, unsigned tid, int debug_uid,
                               int signal)
@@ -407,6 +574,11 @@
     int fd;
     bool need_cleanup = false;
 
+    /* don't copy log messages to tombstone unless this is a dev device */
+    char value[PROPERTY_VALUE_MAX];
+    property_get("ro.debuggable", value, "0");
+    bool wantLogs = (value[0] == '1');
+
     mkdir(TOMBSTONE_DIR, 0755);
     chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM);
 
@@ -416,6 +588,11 @@
 
     dump_crash_banner(fd, pid, tid, signal);
     dump_crash_report(fd, pid, tid, true);
+
+    if (wantLogs) {
+        dump_logs(fd, pid, true);
+    }
+
     /*
      * If the user has requested to attach gdb, don't collect the per-thread
      * information as it increases the chance to lose track of the process.
@@ -424,6 +601,10 @@
         need_cleanup = dump_sibling_thread_report(fd, pid, tid);
     }
 
+    if (wantLogs) {
+        dump_logs(fd, pid, false);
+    }
+
     close(fd);
     return need_cleanup;
 }
@@ -587,9 +768,11 @@
      * is blocked in a read() call. This gives us the time to PTRACE_ATTACH
      * to it before it has a chance to really fault.
      *
-     * After the attach, the thread is stopped, and we write to the file
-     * descriptor to ensure that it will run as soon as we call PTRACE_CONT
-     * below. See details in bionic/libc/linker/debugger.c, in function
+     * The PTRACE_ATTACH sends a SIGSTOP to the target process, but it
+     * won't necessarily have stopped by the time ptrace() returns.  (We
+     * currently assume it does.)  We write to the file descriptor to
+     * ensure that it can run as soon as we call PTRACE_CONT below.
+     * See details in bionic/libc/linker/debugger.c, in function
      * debugger_signal_handler().
      */
     tid_attach_status = ptrace(PTRACE_ATTACH, tid, 0, 0);
@@ -697,7 +880,12 @@
         wait_for_user_action(tid, &cr);
     }
 
-    /* resume stopped process (so it can crash in peace) */
+    /*
+     * Resume stopped process (so it can crash in peace).  If we didn't
+     * successfully detach, we're still the parent, and the actual parent
+     * won't receive a death notification via wait(2).  At this point
+     * there's not much we can do about that.
+     */
     kill(cr.pid, SIGCONT);
 
     if (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 */
diff --git a/include/cutils/compiler.h b/include/cutils/compiler.h
index 09112d5..70f884a 100644
--- a/include/cutils/compiler.h
+++ b/include/cutils/compiler.h
@@ -29,4 +29,16 @@
 #   define CC_UNLIKELY( exp )  (__builtin_expect( !!(exp), 0 ))
 #endif
 
+/**
+ * exports marked symbols
+ *
+ * if used on a C++ class declaration, this macro must be inserted
+ * after the "class" keyword. For instance:
+ *
+ * template <typename TYPE>
+ * class ANDROID_API Singleton { }
+ */
+
+#define ANDROID_API __attribute__((visibility("default")))
+
 #endif // ANDROID_CUTILS_COMPILER_H
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 59fed9b..8366c94 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -352,7 +352,6 @@
 {
     entry->tv_sec = buf->sec;
     entry->tv_nsec = buf->nsec;
-    entry->priority = buf->msg[0];
     entry->pid = buf->pid;
     entry->tid = buf->tid;
 
@@ -360,19 +359,49 @@
      * format: <priority:1><tag:N>\0<message:N>\0
      *
      * tag str
-     *   starts at msg+1
+     *   starts at buf->msg+1
      * msg
-     *   starts at msg+1+len(tag)+1
+     *   starts at buf->msg+1+len(tag)+1
+     *
+     * The message may have been truncated by the kernel log driver.
+     * When that happens, we must null-terminate the message ourselves.
      */
-    entry->tag = buf->msg + 1;
-    const size_t tag_len = strlen(entry->tag);
-    const size_t preambleAndNullLen = tag_len + 3;
-    if (buf->len <= preambleAndNullLen) {
-        fprintf(stderr, "+++ LOG: entry corrupt or truncated\n");
+    if (buf->len < 3) {
+        // An well-formed entry must consist of at least a priority
+        // and two null characters
+        fprintf(stderr, "+++ LOG: entry too small\n");
         return -1;
     }
-    entry->messageLen = buf->len - preambleAndNullLen;
-    entry->message = entry->tag + tag_len + 1;
+
+    int msgStart = -1;
+    int msgEnd = -1;
+
+    int i;
+    for (i = 1; i < buf->len; i++) {
+        if (buf->msg[i] == '\0') {
+            if (msgStart == -1) {
+                msgStart = i + 1;
+            } else {
+                msgEnd = i;
+                break;
+            }
+        }
+    }
+
+    if (msgStart == -1) {
+        fprintf(stderr, "+++ LOG: malformed log message\n");
+        return -1;
+    }
+    if (msgEnd == -1) {
+        // incoming message not null-terminated; force it
+        msgEnd = buf->len - 1;
+        buf->msg[msgEnd] = '\0';
+    }
+
+    entry->priority = buf->msg[0];
+    entry->tag = buf->msg + 1;
+    entry->message = buf->msg + msgStart;
+    entry->messageLen = msgEnd - msgStart;
 
     return 0;
 }
@@ -830,7 +859,6 @@
         while(pm < (entry->message + entry->messageLen)) {
             const char *lineStart;
             size_t lineLen;
-
             lineStart = pm;
 
             // Find the next end-of-line in message
diff --git a/libnl_2/handlers.c b/libnl_2/handlers.c
index ec8d512..48dcab4 100644
--- a/libnl_2/handlers.c
+++ b/libnl_2/handlers.c
@@ -39,16 +39,14 @@
 struct nl_cb *nl_cb_clone(struct nl_cb *orig)
 {
 	struct nl_cb *new_cb;
-	int new_refcnt;
 
 	new_cb = nl_cb_alloc(NL_CB_DEFAULT);
 	if (new_cb == NULL)
 		goto fail;
 
-	/* Preserve reference count and copy original */
-	new_refcnt = new_cb->cb_refcnt;
+	/* Copy original and set refcount to 1 */
 	memcpy(new_cb, orig, sizeof(*orig));
-	new_cb->cb_refcnt = new_refcnt;
+	new_cb->cb_refcnt = 1;
 
 	return new_cb;
 fail:
@@ -84,9 +82,9 @@
 
 void nl_cb_put(struct nl_cb *cb)
 {
+	if (!cb)
+		return;
 	cb->cb_refcnt--;
 	if (cb->cb_refcnt <= 0)
 		free(cb);
-
 }
-
diff --git a/libnl_2/netlink.c b/libnl_2/netlink.c
index cc2f88e..ee3d600 100644
--- a/libnl_2/netlink.c
+++ b/libnl_2/netlink.c
@@ -59,15 +59,14 @@
 {
 	int rc = -1;
 	int sk_flags;
-	int RECV_BUF_SIZE;
+	int RECV_BUF_SIZE = getpagesize();
 	int errsv;
 	struct iovec recvmsg_iov;
 	struct msghdr msg;
 
 	/* Allocate buffer */
-	RECV_BUF_SIZE = getpagesize();
 	*buf = (unsigned char *) malloc(RECV_BUF_SIZE);
-	if (!buf) {
+	if (!(*buf)) {
 		rc = -ENOMEM;
 		goto fail;
 	}
@@ -91,8 +90,11 @@
 	errsv = errno;
 	fcntl(sk->s_fd, F_SETFL, sk_flags);
 
-	if (rc < 0)
+	if (rc < 0) {
 		rc = -errsv;
+		free(*buf);
+		*buf = NULL;
+	}
 
 fail:
 	return rc;
@@ -108,7 +110,6 @@
 	int rc, cb_rc = NL_OK, done = 0;
 
 	do {
-
 		unsigned char *buf;
 		int i, rem, flags;
 		struct nlmsghdr *nlh;
@@ -127,7 +128,7 @@
 
 			/* Check for callbacks */
 
-			msg = (struct nl_msg *)malloc(sizeof(struct nl_msg));
+			msg = (struct nl_msg *) malloc(sizeof(struct nl_msg));
 			memset(msg, 0, sizeof(*msg));
 			msg->nm_nlh = nlh;
 
@@ -187,7 +188,6 @@
 			if (done)
 				break;
 		}
-
 		free(buf);
 		buf = NULL;
 
@@ -197,7 +197,7 @@
 
 success:
 fail:
-	return	rc;
+	return rc;
 }
 
 /* Send raw data over netlink socket */
diff --git a/libnl_2/socket.c b/libnl_2/socket.c
index ce54f19..d906cac 100644
--- a/libnl_2/socket.c
+++ b/libnl_2/socket.c
@@ -31,7 +31,7 @@
 }
 
 /* Allocate new netlink socket. */
-struct nl_sock *nl_socket_alloc(void)
+static struct nl_sock *_nl_socket_alloc(void)
 {
 	struct nl_sock *sk;
 	struct timeval tv;
@@ -39,13 +39,13 @@
 
 	sk = (struct nl_sock *) malloc(sizeof(struct nl_sock));
 	if (!sk)
-		goto fail;
+		return NULL;
 	memset(sk, 0, sizeof(*sk));
 
 	/* Get current time */
 
 	if (gettimeofday(&tv, NULL))
-		return NULL;
+		goto fail;
 	else
 		sk->s_seq_next = (int) tv.tv_sec;
 
@@ -59,24 +59,36 @@
 	sk->s_peer.nl_pid = 0; /* Kernel */
 	sk->s_peer.nl_groups = 0; /* No groups */
 
-	cb = (struct nl_cb *) malloc(sizeof(struct nl_cb));
+	return sk;
+fail:
+	free(sk);
+	return NULL;
+}
+
+/* Allocate new netlink socket. */
+struct nl_sock *nl_socket_alloc(void)
+{
+	struct nl_sock *sk = _nl_socket_alloc();
+	struct nl_cb *cb;
+
+	if (!sk)
+		return NULL;
+
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
 	if (!cb)
 		goto cb_fail;
-	memset(cb, 0, sizeof(*cb));
-	sk->s_cb = nl_cb_alloc(NL_CB_DEFAULT);
-
-
+	sk->s_cb = cb;
 	return sk;
 cb_fail:
 	free(sk);
-fail:
 	return NULL;
 }
 
 /* Allocate new socket with custom callbacks. */
 struct nl_sock *nl_socket_alloc_cb(struct nl_cb *cb)
 {
-	struct nl_sock *sk = nl_socket_alloc();
+	struct nl_sock *sk = _nl_socket_alloc();
+
 	if (!sk)
 		return NULL;
 
@@ -84,7 +96,6 @@
 	nl_cb_get(cb);
 
 	return sk;
-
 }
 
 /* Free a netlink socket. */
@@ -116,5 +127,3 @@
 {
 	return sk->s_fd;
 }
-
-
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index fe96976..4beebb7 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -122,7 +122,6 @@
             }
             pm = (ulog_packet_msg_t *)NLMSG_DATA(nh);
             devname = pm->indev_name[0] ? pm->indev_name : pm->outdev_name;
-            SLOGD("QLOG prefix=%s dev=%s\n", pm->prefix, devname);
             asprintf(&mParams[0], "ALERT_NAME=%s", pm->prefix);
             asprintf(&mParams[1], "INTERFACE=%s", devname);
             mSubsystem = strdup("qlog");
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 4cd2151..ae56c41 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -296,6 +296,11 @@
                         fprintf(stderr, "read: Unexpected EOF!\n");
                         exit(EXIT_FAILURE);
                     }
+                    else if (entry->entry.len != ret - sizeof(struct logger_entry)) {
+                        fprintf(stderr, "read: unexpected length. Expected %d, got %d\n",
+                                entry->entry.len, ret - sizeof(struct logger_entry));
+                        exit(EXIT_FAILURE);
+                    }
 
                     entry->entry.msg[entry->entry.len] = '\0';
 
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 46af96c..0d2b7d4 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -64,6 +64,7 @@
     write /proc/sys/kernel/sched_wakeup_granularity_ns 2000000
     write /proc/sys/kernel/sched_compat_yield 1
     write /proc/sys/kernel/sched_child_runs_first 0
+    write /proc/sys/kernel/randomize_va_space 2
 
 # Create cgroup mount points for process groups
     mkdir /dev/cpuctl
@@ -379,6 +380,8 @@
     critical
     onrestart restart zygote
     onrestart restart media
+    onrestart restart surfaceflinger
+    onrestart restart drm
 
 service vold /system/bin/vold
     class core