Merge "ueventd: allow matching symlink names when setting permissions"
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index e7d8268..957e5db 100755
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -162,6 +162,8 @@
 #define VENDOR_ID_SHARP         0x04dd
 // SK Telesys's USB Vendor ID
 #define VENDOR_ID_SK_TELESYS    0x1F53
+// Smartisan's USB Vendor ID
+#define VENDOR_ID_SMARTISAN     0x29a9
 // Sony's USB Vendor ID
 #define VENDOR_ID_SONY          0x054C
 // Sony Ericsson's USB Vendor ID
@@ -258,6 +260,7 @@
     VENDOR_ID_SAMSUNG,
     VENDOR_ID_SHARP,
     VENDOR_ID_SK_TELESYS,
+    VENDOR_ID_SMARTISAN,
     VENDOR_ID_SONY,
     VENDOR_ID_SONY_ERICSSON,
     VENDOR_ID_T_AND_A,
diff --git a/charger/charger.c b/charger/charger.c
index 15add87..47b1c07 100644
--- a/charger/charger.c
+++ b/charger/charger.c
@@ -751,24 +751,33 @@
     /* schedule next screen transition */
     charger->next_screen_transition = now + disp_time;
 
-    /* advance frame cntr to the next valid frame
+    /* advance frame cntr to the next valid frame only if we are charging
      * if necessary, advance cycle cntr, and reset frame cntr
      */
-    batt_anim->cur_frame++;
-
-    /* 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)
+    if (charger->num_supplies_online != 0) {
         batt_anim->cur_frame++;
-    if (batt_anim->cur_frame >= batt_anim->num_frames) {
-        batt_anim->cur_cycle++;
-        batt_anim->cur_frame = 0;
+
+        /* 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;
 
         /* don't reset the cycle counter, since we use that as a signal
          * in a test above to check if animation is over
          */
+        }
+    } else {
+        /* Stop animating if we're not charging.
+         * If we stop it immediately instead of going through this loop, then
+         * the animation would stop somewhere in the middle.
+         */
+        batt_anim->cur_frame = 0;
+        batt_anim->cur_cycle++;
     }
 }
 
diff --git a/debuggerd/backtrace.cpp b/debuggerd/backtrace.cpp
index 50bc167..c4a2143 100644
--- a/debuggerd/backtrace.cpp
+++ b/debuggerd/backtrace.cpp
@@ -49,8 +49,9 @@
   struct tm tm;
   localtime_r(&t, &tm);
   char timestr[64];
+  _LOG(log, logtype::BACKTRACE, "\n\nABI: '%s'\n", ABI_STRING);
   strftime(timestr, sizeof(timestr), "%F %T", &tm);
-  _LOG(log, logtype::BACKTRACE, "\n\n----- pid %d at %s -----\n", pid, timestr);
+  _LOG(log, logtype::BACKTRACE, "\n----- pid %d at %s -----\n", pid, timestr);
 
   if (procname) {
     _LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", procname);
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index ac0c36b..61805c9 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -53,10 +53,10 @@
   int32_t original_si_code;
 };
 
-static void wait_for_user_action(pid_t pid) {
+static void wait_for_user_action(const debugger_request_t &request) {
   // Find out the name of the process that crashed.
   char path[64];
-  snprintf(path, sizeof(path), "/proc/%d/exe", pid);
+  snprintf(path, sizeof(path), "/proc/%d/exe", request.pid);
 
   char exe[PATH_MAX];
   int count;
@@ -67,16 +67,6 @@
     exe[count] = '\0';
   }
 
-  // Turn "/system/bin/app_process" into "app_process".
-  // gdbserver doesn't cope with full paths (though we should fix that
-  // and remove this).
-  char* name = strrchr(exe, '/');
-  if (name == NULL) {
-    name = exe; // No '/' found.
-  } else {
-    ++name; // Skip the '/'.
-  }
-
   // Explain how to attach the debugger.
   ALOGI("********************************************************\n"
         "* Process %d has been suspended while crashing.\n"
@@ -88,7 +78,7 @@
         "* Wait for gdb to start, then press the VOLUME DOWN key\n"
         "* to let the process continue crashing.\n"
         "********************************************************\n",
-        pid, name, pid);
+        request.pid, exe, request.tid);
 
   // Wait for VOLUME DOWN.
   if (init_getevent() == 0) {
@@ -103,7 +93,7 @@
     uninit_getevent();
   }
 
-  ALOGI("debuggerd resuming process %d", pid);
+  ALOGI("debuggerd resuming process %d", request.pid);
 }
 
 static int get_process_info(pid_t tid, pid_t* out_pid, uid_t* out_uid, uid_t* out_gid) {
@@ -333,7 +323,7 @@
         // for user action for the crashing process.
         // in this case, we log a message and turn the debug LED on
         // waiting for a gdb connection (for instance)
-        wait_for_user_action(request.pid);
+        wait_for_user_action(request);
       } else {
         // just detach
         if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 7482886..dea016d 100755
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -58,21 +58,6 @@
 // Must match the path defined in NativeCrashListener.java
 #define NCRASH_SOCKET_PATH "/data/system/ndebugsocket"
 
-// Figure out the abi based on defined macros.
-#if defined(__arm__)
-#define ABI_STRING "arm"
-#elif defined(__aarch64__)
-#define ABI_STRING "arm64"
-#elif defined(__mips__)
-#define ABI_STRING "mips"
-#elif defined(__i386__)
-#define ABI_STRING "x86"
-#elif defined(__x86_64__)
-#define ABI_STRING "x86_64"
-#else
-#error "Unsupported ABI"
-#endif
-
 static bool signal_has_si_addr(int sig) {
   switch (sig) {
     case SIGBUS:
@@ -453,16 +438,16 @@
 // Reads the contents of the specified log device, filters out the entries
 // that don't match the specified pid, and writes them to the tombstone file.
 //
-// If "tail" is set, we only print the last few lines.
+// If "tail" is non-zero, log the last "tail" number of lines.
 static EventTagMap* g_eventTagMap = NULL;
 
-static void dump_log_file(log_t* log, pid_t pid, const char* filename,
-  unsigned int tail) {
+static void dump_log_file(
+    log_t* log, pid_t pid, const char* filename, unsigned int tail) {
   bool first = true;
-  struct logger_list *logger_list;
+  struct logger_list* logger_list;
 
   logger_list = android_logger_list_open(
-    android_name_to_log_id(filename), O_RDONLY | O_NONBLOCK, tail, pid);
+      android_name_to_log_id(filename), O_RDONLY | O_NONBLOCK, tail, pid);
 
   if (!logger_list) {
     ALOGE("Unable to open %s: %s\n", filename, strerror(errno));
@@ -473,6 +458,7 @@
 
   while (true) {
     ssize_t actual = android_logger_list_read(logger_list, &log_entry);
+    struct logger_entry* entry;
 
     if (actual < 0) {
       if (actual == -EINTR) {
@@ -496,15 +482,11 @@
     // because you will be writing as fast as you're reading.  Any
     // high-frequency debug diagnostics should just be written to
     // the tombstone file.
-    struct logger_entry* entry = &log_entry.entry_v1;
 
-    if (entry->pid != static_cast<int32_t>(pid)) {
-      // wrong pid, ignore
-      continue;
-    }
+    entry = &log_entry.entry_v1;
 
     if (first) {
-      _LOG(log, logtype::HEADER, "--------- %slog %s\n",
+      _LOG(log, logtype::LOGS, "--------- %slog %s\n",
         tail ? "tail end of " : "", filename);
       first = false;
     }
@@ -547,7 +529,7 @@
     // consume any trailing newlines
     char* nl = msg + strlen(msg) - 1;
     while (nl >= msg && *nl == '\n') {
-        *nl-- = '\0';
+      *nl-- = '\0';
     }
 
     char prioChar = (prio < strlen(kPrioChars) ? kPrioChars[prio] : '?');
@@ -564,7 +546,6 @@
       _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8s: %s\n",
          timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
          prioChar, tag, msg);
-
     } while ((msg = nl));
   }
 
@@ -573,7 +554,7 @@
 
 // Dumps the logs generated by the specified pid to the tombstone, from both
 // "system" and "main" log devices.  Ideally we'd interleave the output.
-static void dump_logs(log_t* log, pid_t pid, unsigned tail) {
+static void dump_logs(log_t* log, pid_t pid, unsigned int tail) {
   dump_log_file(log, pid, "system", tail);
   dump_log_file(log, pid, "main", tail);
 }
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index ee4f035..f2e2d29 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -21,6 +21,22 @@
 #include <stdbool.h>
 #include <sys/types.h>
 
+// Figure out the abi based on defined macros.
+#if defined(__arm__)
+#define ABI_STRING "arm"
+#elif defined(__aarch64__)
+#define ABI_STRING "arm64"
+#elif defined(__mips__)
+#define ABI_STRING "mips"
+#elif defined(__i386__)
+#define ABI_STRING "x86"
+#elif defined(__x86_64__)
+#define ABI_STRING "x86_64"
+#else
+#error "Unsupported ABI"
+#endif
+
+
 typedef struct {
     /* tombstone file descriptor */
     int tfd;
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index 9c04c21..266d0b5 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -1216,6 +1216,7 @@
     }
     if (wants_reboot) {
         fb_queue_reboot();
+        fb_queue_wait_for_disconnect();
     } else if (wants_reboot_bootloader) {
         fb_queue_command("reboot-bootloader", "rebooting into bootloader");
         fb_queue_wait_for_disconnect();
diff --git a/include/log/log.h b/include/log/log.h
index 5b76c1a..ace12d6 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -491,7 +491,7 @@
 #endif
 #ifndef LOG_EVENT_STRING
 #define LOG_EVENT_STRING(_tag, _value)                                      \
-    ((void) 0)  /* not implemented -- must combine len with string */
+        (void) __android_log_bswrite(_tag, _value);
 #endif
 /* TODO: something for LIST */
 
diff --git a/include/log/logd.h b/include/log/logd.h
index 379c373..2e6f220 100644
--- a/include/log/logd.h
+++ b/include/log/logd.h
@@ -41,6 +41,7 @@
 int __android_log_bwrite(int32_t tag, const void *payload, size_t len);
 int __android_log_btwrite(int32_t tag, char type, const void *payload,
     size_t len);
+int __android_log_bswrite(int32_t tag, const char *payload);
 
 #ifdef __cplusplus
 }
diff --git a/include/system/window.h b/include/system/window.h
index 16b7b67..31f202f 100644
--- a/include/system/window.h
+++ b/include/system/window.h
@@ -26,8 +26,8 @@
 #include <system/graphics.h>
 #include <unistd.h>
 
-#ifndef __unused
-#define __unused __attribute__((__unused__))
+#ifndef __UNUSED
+#define __UNUSED __attribute__((__unused__))
 #endif
 #ifndef __deprecated
 #define __deprecated __attribute__((__deprecated__))
@@ -610,19 +610,19 @@
 
 /* deprecated. Always returns 0. Don't call. */
 static inline int native_window_connect(
-        struct ANativeWindow* window __unused, int api __unused) __deprecated;
+        struct ANativeWindow* window __UNUSED, int api __UNUSED) __deprecated;
 
 static inline int native_window_connect(
-        struct ANativeWindow* window __unused, int api __unused) {
+        struct ANativeWindow* window __UNUSED, int api __UNUSED) {
     return 0;
 }
 
 /* deprecated. Always returns 0. Don't call. */
 static inline int native_window_disconnect(
-        struct ANativeWindow* window __unused, int api __unused) __deprecated;
+        struct ANativeWindow* window __UNUSED, int api __UNUSED) __deprecated;
 
 static inline int native_window_disconnect(
-        struct ANativeWindow* window __unused, int api __unused) {
+        struct ANativeWindow* window __UNUSED, int api __UNUSED) {
     return 0;
 }
 
diff --git a/init/builtins.c b/init/builtins.c
index 0c32b2a..b32981e 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -862,11 +862,24 @@
 }
 
 int do_loglevel(int nargs, char **args) {
-    if (nargs == 2) {
-        klog_set_level(atoi(args[1]));
-        return 0;
+    int log_level;
+    char log_level_str[PROP_VALUE_MAX] = "";
+    if (nargs != 2) {
+        ERROR("loglevel: missing argument\n");
+        return -EINVAL;
     }
-    return -1;
+
+    if (expand_props(log_level_str, args[1], sizeof(log_level_str))) {
+        ERROR("loglevel: cannot expand '%s'\n", args[1]);
+        return -EINVAL;
+    }
+    log_level = atoi(log_level_str);
+    if (log_level < KLOG_ERROR_LEVEL || log_level > KLOG_DEBUG_LEVEL) {
+        ERROR("loglevel: invalid log level'%d'\n", log_level);
+        return -EINVAL;
+    }
+    klog_set_level(log_level);
+    return 0;
 }
 
 int do_load_persist_props(int nargs, char **args) {
diff --git a/init/init.c b/init/init.c
index 97c33e4..e4ac1cf 100644
--- a/init/init.c
+++ b/init/init.c
@@ -528,7 +528,8 @@
 
 void execute_one_command(void)
 {
-    int ret;
+    int ret, i;
+    char cmd_str[256] = "";
 
     if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {
         cur_action = action_remove_queue_head();
@@ -545,7 +546,17 @@
         return;
 
     ret = cur_command->func(cur_command->nargs, cur_command->args);
-    INFO("command '%s' r=%d\n", cur_command->args[0], ret);
+    if (klog_get_level() >= KLOG_INFO_LEVEL) {
+        for (i = 0; i < cur_command->nargs; i++) {
+            strlcat(cmd_str, cur_command->args[i], sizeof(cmd_str));
+            if (i < cur_command->nargs - 1) {
+                strlcat(cmd_str, " ", sizeof(cmd_str));
+            }
+        }
+        INFO("command '%s' action=%s status=%d (%s:%d)\n",
+             cmd_str, cur_action ? cur_action->name : "", ret, cur_command->filename,
+             cur_command->line);
+    }
 }
 
 static int wait_for_coldboot_done_action(int nargs, char **args)
@@ -938,7 +949,7 @@
     return 0;
 }
 
-static int log_callback(int type, const char *fmt, ...)
+int log_callback(int type, const char *fmt, ...)
 {
     int level;
     va_list ap;
diff --git a/init/init.h b/init/init.h
index c241912..a7615a3 100644
--- a/init/init.h
+++ b/init/init.h
@@ -29,10 +29,14 @@
     struct listnode clist;
 
     int (*func)(int nargs, char **args);
+
+    int line;
+    const char *filename;
+
     int nargs;
     char *args[1];
 };
-    
+
 struct action {
         /* node in list of all actions */
     struct listnode alist;
@@ -43,7 +47,7 @@
 
     unsigned hash;
     const char *name;
-    
+
     struct listnode commands;
     struct command *current;
 };
diff --git a/init/init_parser.c b/init/init_parser.c
index 289e759..6466db2 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -33,9 +33,6 @@
 #include <cutils/iosched_policy.h>
 #include <cutils/list.h>
 
-#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
-#include <sys/_system_properties.h>
-
 static list_declare(service_list);
 static list_declare(action_list);
 static list_declare(action_queue);
@@ -584,6 +581,7 @@
     cmd = calloc(1, sizeof(*cmd));
     cmd->func = func;
     cmd->args[0] = name;
+    cmd->nargs = 1;
     list_add_tail(&act->commands, &cmd->clist);
 
     list_add_tail(&action_list, &act->alist);
@@ -870,6 +868,8 @@
     }
     cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
     cmd->func = kw_func(kw);
+    cmd->line = state->line;
+    cmd->filename = state->filename;
     cmd->nargs = nargs;
     memcpy(cmd->args, args, sizeof(char*) * nargs);
     list_add_tail(&act->commands, &cmd->clist);
diff --git a/init/log.h b/init/log.h
index 0ba770f..e9cb65a 100644
--- a/init/log.h
+++ b/init/log.h
@@ -23,4 +23,6 @@
 #define NOTICE(x...)  KLOG_NOTICE("init", x)
 #define INFO(x...)    KLOG_INFO("init", x)
 
+extern int log_callback(int type, const char *fmt, ...);
+
 #endif
diff --git a/init/property_service.c b/init/property_service.c
index a6cbde4..d112699 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -55,64 +55,6 @@
 
 static int property_set_fd = -1;
 
-/* White list of permissions for setting property services. */
-struct {
-    const char *prefix;
-    unsigned int uid;
-    unsigned int gid;
-} property_perms[] = {
-    { "net.rmnet0.",      AID_RADIO,    0 },
-    { "net.gprs.",        AID_RADIO,    0 },
-    { "net.ppp",          AID_RADIO,    0 },
-    { "net.qmi",          AID_RADIO,    0 },
-    { "net.lte",          AID_RADIO,    0 },
-    { "net.cdma",         AID_RADIO,    0 },
-    { "ril.",             AID_RADIO,    0 },
-    { "gsm.",             AID_RADIO,    0 },
-    { "persist.radio",    AID_RADIO,    0 },
-    { "net.dns",          AID_RADIO,    0 },
-    { "sys.usb.config",   AID_RADIO,    0 },
-    { "net.",             AID_SYSTEM,   0 },
-    { "dev.",             AID_SYSTEM,   0 },
-    { "runtime.",         AID_SYSTEM,   0 },
-    { "hw.",              AID_SYSTEM,   0 },
-    { "sys.",             AID_SYSTEM,   0 },
-    { "sys.powerctl",     AID_SHELL,    0 },
-    { "service.",         AID_SYSTEM,   0 },
-    { "wlan.",            AID_SYSTEM,   0 },
-    { "gps.",             AID_GPS,      0 },
-    { "bluetooth.",       AID_BLUETOOTH,   0 },
-    { "dhcp.",            AID_SYSTEM,   0 },
-    { "dhcp.",            AID_DHCP,     0 },
-    { "debug.",           AID_SYSTEM,   0 },
-    { "debug.",           AID_SHELL,    0 },
-    { "log.",             AID_SHELL,    0 },
-    { "service.adb.root", AID_SHELL,    0 },
-    { "service.adb.tcp.port", AID_SHELL,    0 },
-    { "persist.logd.size",AID_SYSTEM,   0 },
-    { "persist.sys.",     AID_SYSTEM,   0 },
-    { "persist.service.", AID_SYSTEM,   0 },
-    { "persist.security.", AID_SYSTEM,   0 },
-    { "persist.gps.",      AID_GPS,      0 },
-    { "persist.service.bdroid.", AID_BLUETOOTH,   0 },
-    { "selinux."         , AID_SYSTEM,   0 },
-    { NULL, 0, 0 }
-};
-
-/*
- * White list of UID that are allowed to start/stop services.
- * Currently there are no user apps that require.
- */
-struct {
-    const char *service;
-    unsigned int uid;
-    unsigned int gid;
-} control_perms[] = {
-    { "dumpstate",AID_SHELL, AID_LOG },
-    { "ril-daemon",AID_RADIO, AID_RADIO },
-     {NULL, 0, 0 }
-};
-
 typedef struct {
     size_t size;
     int fd;
@@ -194,34 +136,10 @@
 }
 
 /*
- * Checks permissions for starting/stoping system services.
- * AID_SYSTEM and AID_ROOT are always allowed.
- *
- * Returns 1 if uid allowed, 0 otherwise.
- */
-static int check_control_perms(const char *name, unsigned int uid, unsigned int gid, char *sctx) {
-
-    int i;
-    if (uid == AID_SYSTEM || uid == AID_ROOT)
-      return check_control_mac_perms(name, sctx);
-
-    /* Search the ACL */
-    for (i = 0; control_perms[i].service; i++) {
-        if (strcmp(control_perms[i].service, name) == 0) {
-            if ((uid && control_perms[i].uid == uid) ||
-                (gid && control_perms[i].gid == gid)) {
-                return check_control_mac_perms(name, sctx);
-            }
-        }
-    }
-    return 0;
-}
-
-/*
  * Checks permissions for setting system properties.
  * Returns 1 if uid allowed, 0 otherwise.
  */
-static int check_perms(const char *name, unsigned int uid, unsigned int gid, char *sctx)
+static int check_perms(const char *name, char *sctx)
 {
     int i;
     unsigned int app_id;
@@ -229,26 +147,7 @@
     if(!strncmp(name, "ro.", 3))
         name +=3;
 
-    if (uid == 0)
-        return check_mac_perms(name, sctx);
-
-    app_id = multiuser_get_app_id(uid);
-    if (app_id == AID_BLUETOOTH) {
-        uid = app_id;
-    }
-
-    for (i = 0; property_perms[i].prefix; i++) {
-        if (strncmp(property_perms[i].prefix, name,
-                    strlen(property_perms[i].prefix)) == 0) {
-            if ((uid && property_perms[i].uid == uid) ||
-                (gid && property_perms[i].gid == gid)) {
-
-                return check_mac_perms(name, sctx);
-            }
-        }
-    }
-
-    return 0;
+    return check_mac_perms(name, sctx);
 }
 
 int __property_get(const char *name, char *value)
@@ -406,14 +305,14 @@
             // Keep the old close-socket-early behavior when handling
             // ctl.* properties.
             close(s);
-            if (check_control_perms(msg.value, cr.uid, cr.gid, source_ctx)) {
+            if (check_control_mac_perms(msg.value, source_ctx)) {
                 handle_control_message((char*) msg.name + 4, (char*) msg.value);
             } else {
                 ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n",
                         msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);
             }
         } else {
-            if (check_perms(msg.name, cr.uid, cr.gid, source_ctx)) {
+            if (check_perms(msg.name, source_ctx)) {
                 property_set((char*) msg.name, (char*) msg.value);
             } else {
                 ERROR("sys_prop: permission denied uid:%d  name:%s\n",
diff --git a/init/ueventd.c b/init/ueventd.c
index 4ad0cb9..833e4fd 100644
--- a/init/ueventd.c
+++ b/init/ueventd.c
@@ -21,6 +21,7 @@
 #include <stdio.h>
 #include <ctype.h>
 #include <signal.h>
+#include <selinux/selinux.h>
 
 #include <private/android_filesystem_config.h>
 
@@ -76,6 +77,10 @@
     }
 #endif
 
+    union selinux_callback cb;
+    cb.func_log = log_callback;
+    selinux_set_callback(SELINUX_CB_LOG, cb);
+
     INFO("starting ueventd\n");
 
     /* Respect hardware passed in through the kernel cmd line. Here we will look
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index 1de81e7..c321369 100755
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -201,6 +201,8 @@
 LOCAL_SRC_FILES := \
 	BacktraceMap.cpp \
 
+LOCAL_MULTILIB := both
+
 include $(BUILD_HOST_SHARED_LIBRARY)
 
 endif # TARGET_BUILD_APPS
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index c0faed4..933a77b 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -134,6 +134,9 @@
 LOCAL_SRC_FILES_arm += \
         arch-arm/memset32.S \
 
+LOCAL_SRC_FILES_arm64 += \
+        arch-arm64/android_memset.S \
+
 LOCAL_SRC_FILES_mips += \
         arch-mips/android_memset.c \
 
@@ -146,6 +149,7 @@
         arch-x86_64/android_memset32_SSE2-atom.S \
 
 LOCAL_CFLAGS_arm += -DHAVE_MEMSET16 -DHAVE_MEMSET32
+LOCAL_CFLAGS_arm64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
 LOCAL_CFLAGS_mips += -DHAVE_MEMSET16 -DHAVE_MEMSET32
 LOCAL_CFLAGS_x86 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
 LOCAL_CFLAGS_x86_64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
diff --git a/libcutils/arch-arm/memset32.S b/libcutils/arch-arm/memset32.S
index 4697265..6efab9f 100644
--- a/libcutils/arch-arm/memset32.S
+++ b/libcutils/arch-arm/memset32.S
@@ -51,8 +51,10 @@
 
 android_memset32:
         .fnstart
-        .save       {lr}
+        .cfi_startproc
         str         lr, [sp, #-4]!
+        .cfi_def_cfa_offset 4
+        .cfi_rel_offset lr, 0
 
         /* align the destination to a cache-line */
         mov         r12, r1
@@ -89,5 +91,8 @@
         strmih      lr, [r0], #2
 
         ldr         lr, [sp], #4
+        .cfi_def_cfa_offset 0
+        .cfi_restore lr
         bx          lr
+        .cfi_endproc
         .fnend
diff --git a/libcutils/arch-arm64/android_memset.S b/libcutils/arch-arm64/android_memset.S
new file mode 100644
index 0000000..9a83a68
--- /dev/null
+++ b/libcutils/arch-arm64/android_memset.S
@@ -0,0 +1,211 @@
+/* Copyright (c) 2012, Linaro Limited
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+       * Redistributions of source code must retain the above copyright
+         notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above copyright
+         notice, this list of conditions and the following disclaimer in the
+         documentation and/or other materials provided with the distribution.
+       * Neither the name of the Linaro nor the
+         names of its contributors may be used to endorse or promote products
+         derived from this software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* Assumptions:
+ *
+ * ARMv8-a, AArch64
+ * Unaligned accesses
+ *
+ */
+
+/* By default we assume that the DC instruction can be used to zero
+   data blocks more efficiently.  In some circumstances this might be
+   unsafe, for example in an asymmetric multiprocessor environment with
+   different DC clear lengths (neither the upper nor lower lengths are
+   safe to use). */
+
+#define dst  		x0
+#define count		x2
+#define tmp1		x3
+#define tmp1w		w3
+#define tmp2		x4
+#define tmp2w		w4
+#define zva_len_x	x5
+#define zva_len		w5
+#define zva_bits_x	x6
+
+#define A_l		x1
+#define A_lw		w1
+#define tmp3w		w9
+
+#define ENTRY(f) \
+  .text; \
+  .globl f; \
+  .align 0; \
+  .type f, %function; \
+  f: \
+  .cfi_startproc \
+
+#define END(f) \
+  .cfi_endproc; \
+  .size f, .-f; \
+
+ENTRY(android_memset16)
+	ands   A_lw, A_lw, #0xffff
+	b.eq	.Lzero_mem
+	orr	A_lw, A_lw, A_lw, lsl #16
+	b .Lexpand_to_64
+END(android_memset16)
+
+ENTRY(android_memset32)
+	cmp	    A_lw, #0
+	b.eq	.Lzero_mem
+.Lexpand_to_64:
+	orr	A_l, A_l, A_l, lsl #32
+.Ltail_maybe_long:
+	cmp	count, #64
+	b.ge	.Lnot_short
+.Ltail_maybe_tiny:
+	cmp	count, #15
+	b.le	.Ltail15tiny
+.Ltail63:
+	ands	tmp1, count, #0x30
+	b.eq	.Ltail15
+	add	dst, dst, tmp1
+	cmp	tmp1w, #0x20
+	b.eq	1f
+	b.lt	2f
+	stp	A_l, A_l, [dst, #-48]
+1:
+	stp	A_l, A_l, [dst, #-32]
+2:
+	stp	A_l, A_l, [dst, #-16]
+
+.Ltail15:
+	and	count, count, #15
+	add	dst, dst, count
+	stp	A_l, A_l, [dst, #-16]	/* Repeat some/all of last store. */
+	ret
+
+.Ltail15tiny:
+	/* Set up to 15 bytes.  Does not assume earlier memory
+	   being set.  */
+	tbz	count, #3, 1f
+	str	A_l, [dst], #8
+1:
+	tbz	count, #2, 1f
+	str	A_lw, [dst], #4
+1:
+	tbz	count, #1, 1f
+	strh	A_lw, [dst], #2
+1:
+	ret
+
+	/* Critical loop.  Start at a new cache line boundary.  Assuming
+	 * 64 bytes per line, this ensures the entire loop is in one line.  */
+	.p2align 6
+.Lnot_short:
+	neg	tmp2, dst
+	ands	tmp2, tmp2, #15
+	b.eq	2f
+	/* Bring DST to 128-bit (16-byte) alignment.  We know that there's
+	 * more than that to set, so we simply store 16 bytes and advance by
+	 * the amount required to reach alignment.  */
+	sub	count, count, tmp2
+	stp	A_l, A_l, [dst]
+	add	dst, dst, tmp2
+	/* There may be less than 63 bytes to go now.  */
+	cmp	count, #63
+	b.le	.Ltail63
+2:
+	sub	dst, dst, #16		/* Pre-bias.  */
+	sub	count, count, #64
+1:
+	stp	A_l, A_l, [dst, #16]
+	stp	A_l, A_l, [dst, #32]
+	stp	A_l, A_l, [dst, #48]
+	stp	A_l, A_l, [dst, #64]!
+	subs	count, count, #64
+	b.ge	1b
+	tst	count, #0x3f
+	add	dst, dst, #16
+	b.ne	.Ltail63
+	ret
+
+	/* For zeroing memory, check to see if we can use the ZVA feature to
+	 * zero entire 'cache' lines.  */
+.Lzero_mem:
+	mov	A_l, #0
+	cmp	count, #63
+	b.le	.Ltail_maybe_tiny
+	neg	tmp2, dst
+	ands	tmp2, tmp2, #15
+	b.eq	1f
+	sub	count, count, tmp2
+	stp	A_l, A_l, [dst]
+	add	dst, dst, tmp2
+	cmp	count, #63
+	b.le	.Ltail63
+1:
+	/* For zeroing small amounts of memory, it's not worth setting up
+	 * the line-clear code.  */
+	cmp	count, #128
+	b.lt	.Lnot_short
+	mrs	tmp1, dczid_el0
+	tbnz	tmp1, #4, .Lnot_short
+	mov	tmp3w, #4
+	and	zva_len, tmp1w, #15	/* Safety: other bits reserved.  */
+	lsl	zva_len, tmp3w, zva_len
+
+.Lzero_by_line:
+	/* Compute how far we need to go to become suitably aligned.  We're
+	 * already at quad-word alignment.  */
+	cmp	count, zva_len_x
+	b.lt	.Lnot_short		/* Not enough to reach alignment.  */
+	sub	zva_bits_x, zva_len_x, #1
+	neg	tmp2, dst
+	ands	tmp2, tmp2, zva_bits_x
+	b.eq	1f			/* Already aligned.  */
+	/* Not aligned, check that there's enough to copy after alignment.  */
+	sub	tmp1, count, tmp2
+	cmp	tmp1, #64
+	ccmp	tmp1, zva_len_x, #8, ge	/* NZCV=0b1000 */
+	b.lt	.Lnot_short
+	/* We know that there's at least 64 bytes to zero and that it's safe
+	 * to overrun by 64 bytes.  */
+	mov	count, tmp1
+2:
+	stp	A_l, A_l, [dst]
+	stp	A_l, A_l, [dst, #16]
+	stp	A_l, A_l, [dst, #32]
+	subs	tmp2, tmp2, #64
+	stp	A_l, A_l, [dst, #48]
+	add	dst, dst, #64
+	b.ge	2b
+	/* We've overrun a bit, so adjust dst downwards.  */
+	add	dst, dst, tmp2
+1:
+	sub	count, count, zva_len_x
+3:
+	dc	zva, dst
+	add	dst, dst, zva_len_x
+	subs	count, count, zva_len_x
+	b.ge	3b
+	ands	count, count, zva_bits_x
+	b.ne	.Ltail_maybe_long
+	ret
+END(android_memset32)
diff --git a/libcutils/tests/Android.mk b/libcutils/tests/Android.mk
index d3e07f8..8e65310 100644
--- a/libcutils/tests/Android.mk
+++ b/libcutils/tests/Android.mk
@@ -13,20 +13,36 @@
 # limitations under the License.
 
 LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
 
 test_src_files := \
+    MemsetTest.cpp \
     PropertiesTest.cpp \
 
-shared_libraries := \
-    libutils \
-    liblog
-
-static_libraries := \
-    libcutils
-
-LOCAL_SHARED_LIBRARIES := $(shared_libraries)
-LOCAL_STATIC_LIBRARIES := $(static_libraries)
-LOCAL_SRC_FILES := $(test_src_files)
+include $(CLEAR_VARS)
 LOCAL_MODULE := libcutils_test
+LOCAL_SRC_FILES := $(test_src_files)
+LOCAL_SHARED_LIBRARIES := \
+    libcutils \
+    liblog \
+    libutils \
+
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcutils_test_static
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_SRC_FILES := $(test_src_files)
+LOCAL_STATIC_LIBRARIES := \
+    libc \
+    libcutils \
+    liblog \
+    libstlport_static \
+    libutils \
+
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 include $(BUILD_NATIVE_TEST)
diff --git a/libcutils/tests/MemsetTest.cpp b/libcutils/tests/MemsetTest.cpp
new file mode 100644
index 0000000..45efc51
--- /dev/null
+++ b/libcutils/tests/MemsetTest.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <cutils/memory.h>
+#include <gtest/gtest.h>
+
+#define FENCEPOST_LENGTH 8
+
+#define MAX_TEST_SIZE (64*1024)
+// Choose values that have no repeating byte values.
+#define MEMSET16_PATTERN 0xb139
+#define MEMSET32_PATTERN 0x48193a27
+
+enum test_e {
+  MEMSET16 = 0,
+  MEMSET32,
+};
+
+static int g_memset16_aligns[][2] = {
+  { 2, 0 },
+  { 4, 0 },
+  { 8, 0 },
+  { 16, 0 },
+  { 32, 0 },
+  { 64, 0 },
+  { 128, 0 },
+
+  { 4, 2 },
+
+  { 8, 2 },
+  { 8, 4 },
+  { 8, 6 },
+
+  { 128, 2 },
+  { 128, 4 },
+  { 128, 6 },
+  { 128, 8 },
+  { 128, 10 },
+  { 128, 12 },
+  { 128, 14 },
+  { 128, 16 },
+};
+
+static int g_memset32_aligns[][2] = {
+  { 4, 0 },
+  { 8, 0 },
+  { 16, 0 },
+  { 32, 0 },
+  { 64, 0 },
+  { 128, 0 },
+
+  { 8, 4 },
+
+  { 128, 4 },
+  { 128, 8 },
+  { 128, 12 },
+  { 128, 16 },
+};
+
+static size_t GetIncrement(size_t len, size_t min_incr) {
+  if (len >= 4096) {
+    return 1024;
+  } else if (len >= 1024) {
+    return 256;
+  }
+  return min_incr;
+}
+
+// Return a pointer into the current buffer with the specified alignment.
+static void *GetAlignedPtr(void *orig_ptr, int alignment, int or_mask) {
+  uint64_t ptr = reinterpret_cast<uint64_t>(orig_ptr);
+  if (alignment > 0) {
+      // When setting the alignment, set it to exactly the alignment chosen.
+      // The pointer returned will be guaranteed not to be aligned to anything
+      // more than that.
+      ptr += alignment - (ptr & (alignment - 1));
+      ptr |= alignment | or_mask;
+  }
+
+  return reinterpret_cast<void*>(ptr);
+}
+
+static void SetFencepost(uint8_t *buffer) {
+  for (int i = 0; i < FENCEPOST_LENGTH; i += 2) {
+    buffer[i] = 0xde;
+    buffer[i+1] = 0xad;
+  }
+}
+
+static void VerifyFencepost(uint8_t *buffer) {
+  for (int i = 0; i < FENCEPOST_LENGTH; i += 2) {
+    if (buffer[i] != 0xde || buffer[i+1] != 0xad) {
+      uint8_t expected_value;
+      if (buffer[i] == 0xde) {
+        i++;
+        expected_value = 0xad;
+      } else {
+        expected_value = 0xde;
+      }
+      ASSERT_EQ(expected_value, buffer[i]);
+    }
+  }
+}
+
+void RunMemsetTests(test_e test_type, uint32_t value, int align[][2], size_t num_aligns) {
+  size_t min_incr = 4;
+  if (test_type == MEMSET16) {
+    min_incr = 2;
+    value |= value << 16;
+  }
+  uint32_t* expected_buf = new uint32_t[MAX_TEST_SIZE/sizeof(uint32_t)];
+  for (size_t i = 0; i < MAX_TEST_SIZE/sizeof(uint32_t); i++) {
+    expected_buf[i] = value;
+  }
+
+  // Allocate one large buffer with lots of extra space so that we can
+  // guarantee that all possible alignments will fit.
+  uint8_t *buf = new uint8_t[3*MAX_TEST_SIZE];
+  uint8_t *buf_align;
+  for (size_t i = 0; i < num_aligns; i++) {
+    size_t incr = min_incr;
+    for (size_t len = incr; len <= MAX_TEST_SIZE; len += incr) {
+      incr = GetIncrement(len, min_incr);
+
+      buf_align = reinterpret_cast<uint8_t*>(GetAlignedPtr(
+          buf+FENCEPOST_LENGTH, align[i][0], align[i][1]));
+
+      SetFencepost(&buf_align[-FENCEPOST_LENGTH]);
+      SetFencepost(&buf_align[len]);
+
+      memset(buf_align, 0xff, len);
+      if (test_type == MEMSET16) {
+        android_memset16(reinterpret_cast<uint16_t*>(buf_align), value, len);
+      } else {
+        android_memset32(reinterpret_cast<uint32_t*>(buf_align), value, len);
+      }
+      ASSERT_EQ(0, memcmp(expected_buf, buf_align, len))
+          << "Failed size " << len << " align " << align[i][0] << " " << align[i][1] << "\n";
+
+      VerifyFencepost(&buf_align[-FENCEPOST_LENGTH]);
+      VerifyFencepost(&buf_align[len]);
+    }
+  }
+  delete expected_buf;
+  delete buf;
+}
+
+TEST(libcutils, android_memset16_non_zero) {
+  RunMemsetTests(MEMSET16, MEMSET16_PATTERN, g_memset16_aligns, sizeof(g_memset16_aligns)/sizeof(int[2]));
+}
+
+TEST(libcutils, android_memset16_zero) {
+  RunMemsetTests(MEMSET16, 0, g_memset16_aligns, sizeof(g_memset16_aligns)/sizeof(int[2]));
+}
+
+TEST(libcutils, android_memset32_non_zero) {
+  RunMemsetTests(MEMSET32, MEMSET32_PATTERN, g_memset32_aligns, sizeof(g_memset32_aligns)/sizeof(int[2]));
+}
+
+TEST(libcutils, android_memset32_zero) {
+  RunMemsetTests(MEMSET32, 0, g_memset32_aligns, sizeof(g_memset32_aligns)/sizeof(int[2]));
+}
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index f10eb8e..1da55ab 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -473,3 +473,25 @@
 
     return write_to_log(LOG_ID_EVENTS, vec, 3);
 }
+
+/*
+ * Like __android_log_bwrite, but used for writing strings to the
+ * event log.
+ */
+int __android_log_bswrite(int32_t tag, const char *payload)
+{
+    struct iovec vec[4];
+    char type = EVENT_TYPE_STRING;
+    uint32_t len = strlen(payload);
+
+    vec[0].iov_base = &tag;
+    vec[0].iov_len = sizeof(tag);
+    vec[1].iov_base = &type;
+    vec[1].iov_len = sizeof(type);
+    vec[2].iov_base = &len;
+    vec[2].iov_len = sizeof(len);
+    vec[3].iov_base = (void*)payload;
+    vec[3].iov_len = len;
+
+    return write_to_log(LOG_ID_EVENTS, vec, 4);
+}
diff --git a/liblog/logd_write_kern.c b/liblog/logd_write_kern.c
index 1d10748..1ed5ecf 100644
--- a/liblog/logd_write_kern.c
+++ b/liblog/logd_write_kern.c
@@ -317,3 +317,25 @@
 
     return write_to_log(LOG_ID_EVENTS, vec, 3);
 }
+
+/*
+ * Like __android_log_bwrite, but used for writing strings to the
+ * event log.
+ */
+int __android_log_bswrite(int32_t tag, const char *payload)
+{
+    struct iovec vec[4];
+    char type = EVENT_TYPE_STRING;
+    uint32_t len = strlen(payload);
+
+    vec[0].iov_base = &tag;
+    vec[0].iov_len = sizeof(tag);
+    vec[1].iov_base = &type;
+    vec[1].iov_len = sizeof(type);
+    vec[2].iov_base = &len;
+    vec[2].iov_len = sizeof(len);
+    vec[3].iov_base = (void*)payload;
+    vec[3].iov_len = len;
+
+    return write_to_log(LOG_ID_EVENTS, vec, 4);
+}
diff --git a/libpixelflinger/codeflinger/CodeCache.cpp b/libpixelflinger/codeflinger/CodeCache.cpp
index 8afe0a9..cfd2b370 100644
--- a/libpixelflinger/codeflinger/CodeCache.cpp
+++ b/libpixelflinger/codeflinger/CodeCache.cpp
@@ -201,9 +201,9 @@
         mCacheInUse += assemblySize;
         mWhen++;
         // synchronize caches...
-        const long base = long(assembly->base());
-        const long curr = base + long(assembly->size());
-        __builtin___clear_cache((void*)base, (void*)curr);
+        void* base = assembly->base();
+        void* curr = (uint8_t*)base + assembly->size();
+        __builtin___clear_cache(base, curr);
     }
 
     pthread_mutex_unlock(&mLock);
diff --git a/libpixelflinger/tests/arch-arm64/assembler/Android.mk b/libpixelflinger/tests/arch-arm64/assembler/Android.mk
index 36db49c..eca36ef 100644
--- a/libpixelflinger/tests/arch-arm64/assembler/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/assembler/Android.mk
@@ -16,4 +16,6 @@
 
 LOCAL_MODULE_TAGS := tests
 
-include $(BUILD_EXECUTABLE)
+LOCAL_MULTILIB := 64
+
+include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk b/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
index ac890c7..3368eb0 100644
--- a/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
@@ -13,4 +13,6 @@
 
 LOCAL_MODULE_TAGS := tests
 
-include $(BUILD_EXECUTABLE)
+LOCAL_MULTILIB := 64
+
+include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/arch-arm64/disassembler/Android.mk b/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
index baf4070..8f62f09 100644
--- a/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
@@ -14,4 +14,6 @@
 
 LOCAL_MODULE_TAGS := tests
 
-include $(BUILD_EXECUTABLE)
+LOCAL_MULTILIB := 64
+
+include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
index 1cce1bd..8e5ec5e 100644
--- a/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
@@ -13,4 +13,6 @@
 
 LOCAL_MODULE_TAGS := tests
 
-include $(BUILD_EXECUTABLE)
+LOCAL_MULTILIB := 64
+
+include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/codegen/Android.mk b/libpixelflinger/tests/codegen/Android.mk
index aa320fc..bc07015 100644
--- a/libpixelflinger/tests/codegen/Android.mk
+++ b/libpixelflinger/tests/codegen/Android.mk
@@ -15,4 +15,4 @@
 
 LOCAL_MODULE_TAGS := tests
 
-include $(BUILD_EXECUTABLE)
+include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/gglmul/Android.mk b/libpixelflinger/tests/gglmul/Android.mk
index 64f88b7..f479fa1 100644
--- a/libpixelflinger/tests/gglmul/Android.mk
+++ b/libpixelflinger/tests/gglmul/Android.mk
@@ -13,4 +13,4 @@
 
 LOCAL_MODULE_TAGS := tests
 
-include $(BUILD_EXECUTABLE)
+include $(BUILD_NATIVE_TEST)
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 08b08fe..a2c9c0f 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -428,6 +428,9 @@
 on nonencrypted
     class_start late_start
 
+on property:sys.init_log_level=*
+    loglevel ${sys.init_log_level}
+
 on charger
     class_start charger
 
diff --git a/toolbox/nandread.c b/toolbox/nandread.c
index 971c232..bd19942 100644
--- a/toolbox/nandread.c
+++ b/toolbox/nandread.c
@@ -1,9 +1,10 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
 #include <mtd/mtd-user.h>
@@ -189,18 +190,18 @@
     for (pos = start, opos = 0; pos < end; pos += mtdinfo.writesize) {
         bad_block = 0;
         if (verbose > 3)
-            printf("reading at %llx\n", pos);
+            printf("reading at %" PRIx64 "\n", pos);
         lseek64(fd, pos, SEEK_SET);
         ret = read(fd, buffer, mtdinfo.writesize + rawmode);
         if (ret < (int)mtdinfo.writesize) {
-            fprintf(stderr, "short read at %llx, %d\n", pos, ret);
+            fprintf(stderr, "short read at %" PRIx64 ", %d\n", pos, ret);
             bad_block = 2;
         }
         if (!rawmode) {
             oobbuf.start = pos;
             ret = ioctl(fd, MEMREADOOB, &oobbuf);
             if (ret) {
-                fprintf(stderr, "failed to read oob data at %llx, %d\n", pos, ret);
+                fprintf(stderr, "failed to read oob data at %" PRIx64 ", %d\n", pos, ret);
                 bad_block = 2;
             }
         }
@@ -213,17 +214,17 @@
         bpos = pos / mtdinfo.erasesize * mtdinfo.erasesize;
         ret = ioctl(fd, MEMGETBADBLOCK, &bpos);
         if (ret && errno != EOPNOTSUPP) {
-            printf("badblock at %llx\n", pos);
+            printf("badblock at %" PRIx64 "\n", pos);
             bad_block = 1;
         }
         if (ecc.corrected != last_ecc.corrected)
-            printf("ecc corrected, %u, at %llx\n", ecc.corrected - last_ecc.corrected, pos);
+            printf("ecc corrected, %u, at %" PRIx64 "\n", ecc.corrected - last_ecc.corrected, pos);
         if (ecc.failed != last_ecc.failed)
-            printf("ecc failed, %u, at %llx\n", ecc.failed - last_ecc.failed, pos);
+            printf("ecc failed, %u, at %" PRIx64 "\n", ecc.failed - last_ecc.failed, pos);
         if (ecc.badblocks != last_ecc.badblocks)
-            printf("ecc badblocks, %u, at %llx\n", ecc.badblocks - last_ecc.badblocks, pos);
+            printf("ecc badblocks, %u, at %" PRIx64 "\n", ecc.badblocks - last_ecc.badblocks, pos);
         if (ecc.bbtblocks != last_ecc.bbtblocks)
-            printf("ecc bbtblocks, %u, at %llx\n", ecc.bbtblocks - last_ecc.bbtblocks, pos);
+            printf("ecc bbtblocks, %u, at %" PRIx64 "\n", ecc.bbtblocks - last_ecc.bbtblocks, pos);
 
         if (!rawmode) {
             oob_fixed = (uint8_t *)oob_data;
@@ -241,18 +242,18 @@
         if (outfd >= 0) {
             ret = write(outfd, buffer, mtdinfo.writesize + spare_size);
             if (ret < (int)(mtdinfo.writesize + spare_size)) {
-                fprintf(stderr, "short write at %llx, %d\n", pos, ret);
+                fprintf(stderr, "short write at %" PRIx64 ", %d\n", pos, ret);
                 close(outfd);
                 outfd = -1;
             }
             if (ecc.corrected != last_ecc.corrected)
-                fprintf(statusfile, "%08llx: ecc corrected\n", opos);
+                fprintf(statusfile, "%08" PRIx64 ": ecc corrected\n", opos);
             if (ecc.failed != last_ecc.failed)
-                fprintf(statusfile, "%08llx: ecc failed\n", opos);
+                fprintf(statusfile, "%08" PRIx64 ": ecc failed\n", opos);
             if (bad_block == 1)
-                fprintf(statusfile, "%08llx: badblock\n", opos);
+                fprintf(statusfile, "%08" PRIx64 ": badblock\n", opos);
             if (bad_block == 2)
-                fprintf(statusfile, "%08llx: read error\n", opos);
+                fprintf(statusfile, "%08" PRIx64 ": read error\n", opos);
             opos += mtdinfo.writesize + spare_size;
         }
 
@@ -261,7 +262,7 @@
         if (test_empty(buffer, mtdinfo.writesize + mtdinfo.oobsize + spare_size))
             empty_pages++;
         else if (verbose > 2 || (verbose > 1 && !(pos & (mtdinfo.erasesize - 1))))
-            printf("page at %llx (%d oobbytes): %08x %08x %08x %08x "
+            printf("page at %" PRIx64 " (%d oobbytes): %08x %08x %08x %08x "
                    "%08x %08x %08x %08x\n", pos, oobbuf.start,
                    oob_data[0], oob_data[1], oob_data[2], oob_data[3],
                    oob_data[4], oob_data[5], oob_data[6], oob_data[7]);