Merge "Update to new minui text API" into cw-f-dev
diff --git a/adb/bugreport.cpp b/adb/bugreport.cpp
index 213fa2e..c348dd5 100644
--- a/adb/bugreport.cpp
+++ b/adb/bugreport.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define TRACE_TAG ADB
+
 #include "bugreport.h"
 
 #include <string>
@@ -45,7 +47,7 @@
           show_progress_(show_progress),
           status_(0),
           line_() {
-        SetLineMessage();
+        SetLineMessage("generating");
     }
 
     void OnStdout(const char* buffer, int length) {
@@ -95,6 +97,7 @@
                                                           OS_PATH_SEPARATOR, dest_file_.c_str());
             }
             std::vector<const char*> srcs{src_file_.c_str()};
+            SetLineMessage("pulling");
             status_ =
                 br_->DoSyncPull(srcs, destination.c_str(), true, line_message_.c_str()) ? 0 : 1;
             if (status_ != 0) {
@@ -109,9 +112,8 @@
     }
 
   private:
-    void SetLineMessage() {
-        line_message_ =
-            android::base::StringPrintf("generating %s", adb_basename(dest_file_).c_str());
+    void SetLineMessage(const std::string& action) {
+        line_message_ = action + " " + adb_basename(dest_file_);
     }
 
     void SetSrcFile(const std::string path) {
@@ -119,7 +121,7 @@
         if (!dest_dir_.empty()) {
             // Only uses device-provided name when user passed a directory.
             dest_file_ = adb_basename(path);
-            SetLineMessage();
+            SetLineMessage("generating");
         }
     }
 
@@ -187,22 +189,30 @@
     if (argc > 2) return usage();
 
     // Gets bugreportz version.
-    std::string bugz_stderr;
-    DefaultStandardStreamsCallback version_callback(nullptr, &bugz_stderr);
+    std::string bugz_stdout, bugz_stderr;
+    DefaultStandardStreamsCallback version_callback(&bugz_stdout, &bugz_stderr);
     int status = SendShellCommand(transport_type, serial, "bugreportz -v", false, &version_callback);
     std::string bugz_version = android::base::Trim(bugz_stderr);
+    std::string bugz_output = android::base::Trim(bugz_stdout);
 
     if (status != 0 || bugz_version.empty()) {
-        // Device does not support bugreportz: if called as 'adb bugreport', just falls out to the
-        // flat-file version
-        if (argc == 1) return SendShellCommand(transport_type, serial, "bugreport", false);
+        D("'bugreportz' -v results: status=%d, stdout='%s', stderr='%s'", status,
+          bugz_output.c_str(), bugz_version.c_str());
+        if (argc == 1) {
+            // Device does not support bugreportz: if called as 'adb bugreport', just falls out to
+            // the flat-file version.
+            fprintf(stderr,
+                    "Failed to get bugreportz version, which is only available on devices "
+                    "running Android 7.0 or later.\nTrying a plain-text bug report instead.\n");
+            return SendShellCommand(transport_type, serial, "bugreport", false);
+        }
 
         // But if user explicitly asked for a zipped bug report, fails instead (otherwise calling
-        // 'bugreport' would generate a lot of output the user might not be prepared to handle)
+        // 'bugreport' would generate a lot of output the user might not be prepared to handle).
         fprintf(stderr,
                 "Failed to get bugreportz version: 'bugreportz -v' returned '%s' (code %d).\n"
-                "If the device runs Android M or below, try 'adb bugreport' instead.\n",
-                bugz_stderr.c_str(), status);
+                "If the device does not run Android 7.0 or above, try 'adb bugreport' instead.\n",
+                bugz_output.c_str(), status);
         return status != 0 ? status : -1;
     }
 
diff --git a/adb/bugreport_test.cpp b/adb/bugreport_test.cpp
index f9a0a5e..1129285 100644
--- a/adb/bugreport_test.cpp
+++ b/adb/bugreport_test.cpp
@@ -36,7 +36,9 @@
 using ::testing::StrEq;
 using ::testing::WithArg;
 using ::testing::internal::CaptureStderr;
+using ::testing::internal::CaptureStdout;
 using ::testing::internal::GetCapturedStderr;
+using ::testing::internal::GetCapturedStdout;
 
 // Empty function so tests don't need to be linked against file_sync_service.cpp, which requires
 // SELinux and its transitive dependencies...
@@ -152,19 +154,28 @@
 
 // Tests when called with invalid number of arguments
 TEST_F(BugreportTest, InvalidNumberArgs) {
-    const char* args[1024] = {"bugreport", "to", "principal"};
+    const char* args[] = {"bugreport", "to", "principal"};
     ASSERT_EQ(-42, br_.DoIt(kTransportLocal, "HannibalLecter", 3, args));
 }
 
 // Tests the 'adb bugreport' option when the device does not support 'bugreportz' - it falls back
 // to the flat-file format ('bugreport' binary on device)
 TEST_F(BugreportTest, NoArgumentsPreNDevice) {
-    ExpectBugreportzVersion("");
+    // clang-format off
+    EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -v", false, _))
+        .WillOnce(DoAll(WithArg<4>(WriteOnStderr("")),
+                        // Write some bogus output on stdout to make sure it's ignored
+                        WithArg<4>(WriteOnStdout("Dude, where is my bugreportz?")),
+                        WithArg<4>(ReturnCallbackDone(0))));
+    // clang-format on
+    std::string bugreport = "Reported the bug was.";
+    CaptureStdout();
     EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreport", false, _))
-        .WillOnce(Return(0));
+        .WillOnce(DoAll(WithArg<4>(WriteOnStdout(bugreport)), Return(0)));
 
-    const char* args[1024] = {"bugreport"};
+    const char* args[] = {"bugreport"};
     ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 1, args));
+    ASSERT_THAT(GetCapturedStdout(), StrEq(bugreport));
 }
 
 // Tests the 'adb bugreport' option when the device supports 'bugreportz' version 1.0 - it will
@@ -178,10 +189,10 @@
         .WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")),
                         WithArg<4>(ReturnCallbackDone())));
     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
-                                true, StrEq("generating da_bugreport.zip")))
+                                true, StrEq("pulling da_bugreport.zip")))
         .WillOnce(Return(true));
 
-    const char* args[1024] = {"bugreport"};
+    const char* args[] = {"bugreport"};
     ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 1, args));
 }
 
@@ -198,10 +209,10 @@
                         WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip\n")),
                         WithArg<4>(ReturnCallbackDone())));
     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
-                                true, StrEq("generating da_bugreport.zip")))
+                                true, StrEq("pulling da_bugreport.zip")))
         .WillOnce(Return(true));
 
-    const char* args[1024] = {"bugreport"};
+    const char* args[] = {"bugreport"};
     ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 1, args));
 }
 
@@ -212,10 +223,10 @@
         .WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip")),
                         WithArg<4>(ReturnCallbackDone())));
     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
-                                true, StrEq("generating file.zip")))
+                                true, StrEq("pulling file.zip")))
         .WillOnce(Return(true));
 
-    const char* args[1024] = {"bugreport", "file.zip"};
+    const char* args[] = {"bugreport", "file.zip"};
     ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
 }
 
@@ -228,10 +239,10 @@
                         WithArg<4>(WriteOnStdout("/bugreport.zip")),
                         WithArg<4>(ReturnCallbackDone())));
     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
-                                true, StrEq("generating file.zip")))
+                                true, StrEq("pulling file.zip")))
         .WillOnce(Return(true));
 
-    const char* args[1024] = {"bugreport", "file.zip"};
+    const char* args[] = {"bugreport", "file.zip"};
     ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
 }
 
@@ -264,10 +275,10 @@
             WithArg<4>(ReturnCallbackDone())));
     // clang-format on
     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
-                                true, StrEq("generating file.zip")))
+                                true, StrEq("pulling file.zip")))
         .WillOnce(Return(true));
 
-    const char* args[1024] = {"bugreport", "file.zip"};
+    const char* args[] = {"bugreport", "file.zip"};
     ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
 }
 
@@ -283,10 +294,10 @@
                         WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")),
                         WithArg<4>(ReturnCallbackDone())));
     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
-                                true, StrEq("generating da_bugreport.zip")))
+                                true, StrEq("pulling da_bugreport.zip")))
         .WillOnce(Return(true));
 
-    const char* args[1024] = {"bugreport", td.path};
+    const char* args[] = {"bugreport", td.path};
     ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
 }
 
@@ -297,10 +308,10 @@
         .WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip\n")),
                         WithArg<4>(ReturnCallbackDone())));
     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
-                                true, StrEq("generating file.zip")))
+                                true, StrEq("pulling file.zip")))
         .WillOnce(Return(true));
 
-    const char* args[1024] = {"bugreport", "file"};
+    const char* args[] = {"bugreport", "file"};
     ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
 }
 
@@ -316,10 +327,10 @@
                         WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")),
                         WithArg<4>(ReturnCallbackDone())));
     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
-                                true, StrEq("generating da_bugreport.zip")))
+                                true, StrEq("pulling da_bugreport.zip")))
         .WillOnce(Return(true));
 
-    const char* args[1024] = {"bugreport", td.path};
+    const char* args[] = {"bugreport", td.path};
     ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
 }
 
@@ -331,7 +342,7 @@
             DoAll(WithArg<4>(WriteOnStdout("FAIL:D'OH!\n")), WithArg<4>(ReturnCallbackDone())));
 
     CaptureStderr();
-    const char* args[1024] = {"bugreport", "file.zip"};
+    const char* args[] = {"bugreport", "file.zip"};
     ASSERT_EQ(-1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
     ASSERT_THAT(GetCapturedStderr(), HasSubstr("D'OH!"));
 }
@@ -346,7 +357,7 @@
                         WithArg<4>(ReturnCallbackDone())));
 
     CaptureStderr();
-    const char* args[1024] = {"bugreport", "file.zip"};
+    const char* args[] = {"bugreport", "file.zip"};
     ASSERT_EQ(-1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
     ASSERT_THAT(GetCapturedStderr(), HasSubstr("D'OH!"));
 }
@@ -360,7 +371,7 @@
                         WithArg<4>(ReturnCallbackDone())));
 
     CaptureStderr();
-    const char* args[1024] = {"bugreport", "file.zip"};
+    const char* args[] = {"bugreport", "file.zip"};
     ASSERT_EQ(-1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
     ASSERT_THAT(GetCapturedStderr(), HasSubstr("bugreportz? What am I, a zombie?"));
 }
@@ -370,7 +381,7 @@
     EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -v", false, _))
         .WillOnce(Return(666));
 
-    const char* args[1024] = {"bugreport", "file.zip"};
+    const char* args[] = {"bugreport", "file.zip"};
     ASSERT_EQ(666, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
 }
 
@@ -378,7 +389,7 @@
 TEST_F(BugreportTest, BugreportzVersionEmpty) {
     ExpectBugreportzVersion("");
 
-    const char* args[1024] = {"bugreport", "file.zip"};
+    const char* args[] = {"bugreport", "file.zip"};
     ASSERT_EQ(-1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
 }
 
@@ -388,7 +399,7 @@
     EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
         .WillOnce(Return(666));
 
-    const char* args[1024] = {"bugreport", "file.zip"};
+    const char* args[] = {"bugreport", "file.zip"};
     ASSERT_EQ(666, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
 }
 
@@ -402,6 +413,6 @@
                                 true, HasSubstr("file.zip")))
         .WillOnce(Return(false));
 
-    const char* args[1024] = {"bugreport", "file.zip"};
+    const char* args[] = {"bugreport", "file.zip"};
     ASSERT_EQ(1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
 }
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 23827de..51d828a 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -1430,6 +1430,16 @@
 #endif
 }
 
+static bool _use_legacy_install() {
+    FeatureSet features;
+    std::string error;
+    if (!adb_get_feature_set(&features, &error)) {
+        fprintf(stderr, "error: %s\n", error.c_str());
+        return true;
+    }
+    return !CanUseFeature(features, kFeatureCmd);
+}
+
 int adb_commandline(int argc, const char **argv) {
     int no_daemon = 0;
     int is_daemon = 0;
@@ -1797,17 +1807,10 @@
     }
     else if (!strcmp(argv[0], "install")) {
         if (argc < 2) return usage();
-        FeatureSet features;
-        std::string error;
-        if (!adb_get_feature_set(&features, &error)) {
-            fprintf(stderr, "error: %s\n", error.c_str());
-            return 1;
+        if (_use_legacy_install()) {
+            return install_app_legacy(transport_type, serial, argc, argv);
         }
-
-        if (CanUseFeature(features, kFeatureCmd)) {
-            return install_app(transport_type, serial, argc, argv);
-        }
-        return install_app_legacy(transport_type, serial, argc, argv);
+        return install_app(transport_type, serial, argc, argv);
     }
     else if (!strcmp(argv[0], "install-multiple")) {
         if (argc < 2) return usage();
@@ -1815,17 +1818,10 @@
     }
     else if (!strcmp(argv[0], "uninstall")) {
         if (argc < 2) return usage();
-        FeatureSet features;
-        std::string error;
-        if (!adb_get_feature_set(&features, &error)) {
-            fprintf(stderr, "error: %s\n", error.c_str());
-            return 1;
+        if (_use_legacy_install()) {
+            return uninstall_app_legacy(transport_type, serial, argc, argv);
         }
-
-        if (CanUseFeature(features, kFeatureCmd)) {
-            return uninstall_app(transport_type, serial, argc, argv);
-        }
-        return uninstall_app_legacy(transport_type, serial, argc, argv);
+        return uninstall_app(transport_type, serial, argc, argv);
     }
     else if (!strcmp(argv[0], "sync")) {
         std::string src;
@@ -2031,7 +2027,6 @@
     int i;
     struct stat sb;
     uint64_t total_size = 0;
-
     // Find all APK arguments starting at end.
     // All other arguments passed through verbatim.
     int first_apk = -1;
@@ -2056,7 +2051,14 @@
         return 1;
     }
 
-    std::string cmd = android::base::StringPrintf("exec:pm install-create -S %" PRIu64, total_size);
+    std::string install_cmd;
+    if (_use_legacy_install()) {
+        install_cmd = "exec:pm";
+    } else {
+        install_cmd = "exec:cmd package";
+    }
+
+    std::string cmd = android::base::StringPrintf("%s install-create -S %" PRIu64, install_cmd.c_str(), total_size);
     for (i = 1; i < first_apk; i++) {
         cmd += " " + escape_arg(argv[i]);
     }
@@ -2098,8 +2100,8 @@
         }
 
         std::string cmd = android::base::StringPrintf(
-                "exec:pm install-write -S %" PRIu64 " %d %d_%s -",
-                static_cast<uint64_t>(sb.st_size), session_id, i, adb_basename(file).c_str());
+                "%s install-write -S %" PRIu64 " %d %d_%s -",
+                install_cmd.c_str(), static_cast<uint64_t>(sb.st_size), session_id, i, adb_basename(file).c_str());
 
         int localFd = adb_open(file, O_RDONLY);
         if (localFd < 0) {
@@ -2134,8 +2136,8 @@
 finalize_session:
     // Commit session if we streamed everything okay; otherwise abandon
     std::string service =
-            android::base::StringPrintf("exec:pm install-%s %d",
-                                        success ? "commit" : "abandon", session_id);
+            android::base::StringPrintf("%s install-%s %d",
+                                        install_cmd.c_str(), success ? "commit" : "abandon", session_id);
     fd = adb_connect(service, &error);
     if (fd < 0) {
         fprintf(stderr, "Connect error for finalize: %s\n", error.c_str());
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 26e0ffc..d547c19 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -169,7 +169,19 @@
 void RecordBootComplete() {
   BootEventRecordStore boot_event_store;
   BootEventRecordStore::BootEventRecord record;
+
   time_t uptime = bootstat::ParseUptime();
+  time_t current_time_utc = time(nullptr);
+
+  if (boot_event_store.GetBootEvent("last_boot_time_utc", &record)) {
+    time_t last_boot_time_utc = record.second;
+    time_t time_since_last_boot = difftime(current_time_utc,
+                                           last_boot_time_utc);
+    boot_event_store.AddBootEventWithValue("time_since_last_boot",
+                                           time_since_last_boot);
+  }
+
+  boot_event_store.AddBootEventWithValue("last_boot_time_utc", current_time_utc);
 
   // The boot_complete metric has two variants: boot_complete and
   // ota_boot_complete.  The latter signifies that the device is booting after
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index c1c3174..2b6cad1 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -116,16 +116,18 @@
 };
 
 static std::string find_item_given_name(const char* img_name, const char* product) {
-    char *dir;
-    char path[PATH_MAX + 128];
+    char path_c_str[PATH_MAX + 128];
 
     if(product) {
-        get_my_path(path);
-        return android::base::StringPrintf("../../../target/product/%s/%s", product, img_name);
+        get_my_path(path_c_str);
+        std::string path = path_c_str;
+        path.erase(path.find_last_of('/'));
+        return android::base::StringPrintf("%s/../../../target/product/%s/%s",
+                                           path.c_str(), product, img_name);
     }
 
-    dir = getenv("ANDROID_PRODUCT_OUT");
-    if((dir == 0) || (dir[0] == 0)) {
+    char *dir = getenv("ANDROID_PRODUCT_OUT");
+    if (dir == nullptr || dir[0] == '\0') {
         die("neither -p product specified nor ANDROID_PRODUCT_OUT set");
     }
 
diff --git a/include/sysutils/FrameworkListener.h b/include/sysutils/FrameworkListener.h
index 18049cd..2137069 100644
--- a/include/sysutils/FrameworkListener.h
+++ b/include/sysutils/FrameworkListener.h
@@ -32,6 +32,7 @@
     int mCommandCount;
     bool mWithSeq;
     FrameworkCommandCollection *mCommands;
+    bool mSkipToNextNullByte;
 
 public:
     FrameworkListener(const char *socketName);
diff --git a/liblog/pmsg_writer.c b/liblog/pmsg_writer.c
index 944feba..b338dca 100644
--- a/liblog/pmsg_writer.c
+++ b/liblog/pmsg_writer.c
@@ -31,6 +31,8 @@
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
+#include <sys/system_properties.h>
+
 #include "config_write.h"
 #include "log_portability.h"
 #include "logger.h"
@@ -51,8 +53,25 @@
     .write = pmsgWrite,
 };
 
+static bool pmsgShouldUse = false;
+
+// Only use pmsg on eng builds
+static bool pmsgIsEng() {
+    char buf[PROP_VALUE_MAX];
+
+    if (__system_property_get("ro.build.type", buf) == 0) {
+        return false;
+    }
+
+    if (!strncmp(buf, "eng", sizeof("eng"))) {
+        return true;
+    }
+    return false;
+}
+
 static int pmsgOpen()
 {
+    pmsgShouldUse = pmsgIsEng();
     if (pmsgLoggerWrite.context.fd < 0) {
         pmsgLoggerWrite.context.fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
     }
@@ -75,7 +94,7 @@
     }
     if ((logId != LOG_ID_SECURITY) &&
             (logId != LOG_ID_EVENTS) &&
-            !__android_log_is_debuggable()) {
+            (!pmsgShouldUse || !__android_log_is_debuggable())) {
         return -EINVAL;
     }
     if (pmsgLoggerWrite.context.fd < 0) {
@@ -105,7 +124,7 @@
     size_t i, payloadSize;
     ssize_t ret;
 
-    if ((logId == LOG_ID_EVENTS) && !__android_log_is_debuggable()) {
+    if ((logId == LOG_ID_EVENTS) && (!pmsgShouldUse || !__android_log_is_debuggable())) {
         if (vec[0].iov_len < 4) {
             return -EINVAL;
         }
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index e7b3dd6..579ead9 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -49,6 +49,7 @@
     errorRate = 0;
     mCommandCount = 0;
     mWithSeq = withSeq;
+    mSkipToNextNullByte = false;
 }
 
 bool FrameworkListener::onDataAvailable(SocketClient *c) {
@@ -59,10 +60,15 @@
     if (len < 0) {
         SLOGE("read() failed (%s)", strerror(errno));
         return false;
-    } else if (!len)
+    } else if (!len) {
         return false;
-   if(buffer[len-1] != '\0')
+    } else if (buffer[len-1] != '\0') {
         SLOGW("String is not zero-terminated");
+        android_errorWriteLog(0x534e4554, "29831647");
+        c->sendMsg(500, "Command too large for buffer", false);
+        mSkipToNextNullByte = true;
+        return false;
+    }
 
     int offset = 0;
     int i;
@@ -70,11 +76,16 @@
     for (i = 0; i < len; i++) {
         if (buffer[i] == '\0') {
             /* IMPORTANT: dispatchCommand() expects a zero-terminated string */
-            dispatchCommand(c, buffer + offset);
+            if (mSkipToNextNullByte) {
+                mSkipToNextNullByte = false;
+            } else {
+                dispatchCommand(c, buffer + offset);
+            }
             offset = i + 1;
         }
     }
 
+    mSkipToNextNullByte = false;
     return true;
 }
 
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index a0b7499..c7506ef 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -26,6 +26,7 @@
 #include <syslog.h>
 
 #include <log/logger.h>
+#include <private/android_filesystem_config.h>
 
 #include "LogBuffer.h"
 #include "LogKlog.h"
@@ -614,7 +615,12 @@
     // Parse pid, tid and uid
     const pid_t pid = sniffPid(&p, len - (p - buf));
     const pid_t tid = pid;
-    const uid_t uid = pid ? logbuf->pidToUid(pid) : 0;
+    uid_t uid = AID_ROOT;
+    if (pid) {
+        logbuf->lock();
+        uid = logbuf->pidToUid(pid);
+        logbuf->unlock();
+    }
 
     // Parse (rules at top) to pull out a tag from the incoming kernel message.
     // Some may view the following as an ugly heuristic, the desire is to
@@ -630,126 +636,124 @@
     const char *tag = "";
     const char *etag = tag;
     size_t taglen = len - (p - buf);
-    if (!isspace(*p) && *p) {
-        const char *bt, *et, *cp;
+    const char *bt = p;
 
-        bt = p;
-        if ((taglen >= 6) && !fast<strncmp>(p, "[INFO]", 6)) {
-            // <PRI>[<TIME>] "[INFO]"<tag> ":" message
-            bt = p + 6;
-            taglen -= 6;
-        }
-        for(et = bt; taglen && *et && (*et != ':') && !isspace(*et); ++et, --taglen) {
-           // skip ':' within [ ... ]
-           if (*et == '[') {
-               while (taglen && *et && *et != ']') {
-                   ++et;
-                   --taglen;
-               }
-            }
-        }
-        for(cp = et; taglen && isspace(*cp); ++cp, --taglen);
-        size_t size;
+    static const char infoBrace[] = "[INFO]";
+    static const size_t infoBraceLen = strlen(infoBrace);
+    if ((taglen >= infoBraceLen) && !fast<strncmp>(p, infoBrace, infoBraceLen)) {
+        // <PRI>[<TIME>] "[INFO]"<tag> ":" message
+        bt = p + infoBraceLen;
+        taglen -= infoBraceLen;
+    }
 
+    const char *et;
+    for (et = bt; taglen && *et && (*et != ':') && !isspace(*et); ++et, --taglen) {
+       // skip ':' within [ ... ]
+       if (*et == '[') {
+           while (taglen && *et && *et != ']') {
+               ++et;
+               --taglen;
+           }
+           if (!taglen) {
+               break;
+           }
+       }
+    }
+    const char *cp;
+    for (cp = et; taglen && isspace(*cp); ++cp, --taglen);
+
+    // Validate tag
+    size_t size = et - bt;
+    if (taglen && size) {
         if (*cp == ':') {
+            // ToDo: handle case insensitive colon separated logging stutter:
+            //       <tag> : <tag>: ...
+
             // One Word
             tag = bt;
             etag = et;
             p = cp + 1;
-        } else if (taglen) {
-            size = et - bt;
-            if ((taglen > size) &&   // enough space for match plus trailing :
-                    (*bt == *cp) &&  // ubber fast<strncmp> pair
-                    fast<strncmp>(bt + 1, cp + 1, size - 1)) {
-                // <PRI>[<TIME>] <tag>_host '<tag>.<num>' : message
-                if (!fast<strncmp>(bt + size - 5, "_host", 5)
-                        && !fast<strncmp>(bt + 1, cp + 1, size - 6)) {
+        } else if ((taglen > size) && (tolower(*bt) == tolower(*cp))) {
+            // clean up any tag stutter
+            if (!fast<strncasecmp>(bt + 1, cp + 1, size - 1)) { // no match
+                // <PRI>[<TIME>] <tag> <tag> : message
+                // <PRI>[<TIME>] <tag> <tag>: message
+                // <PRI>[<TIME>] <tag> '<tag>.<num>' : message
+                // <PRI>[<TIME>] <tag> '<tag><num>' : message
+                // <PRI>[<TIME>] <tag> '<tag><stuff>' : message
+                const char *b = cp;
+                cp += size;
+                taglen -= size;
+                while (--taglen && !isspace(*++cp) && (*cp != ':'));
+                const char *e;
+                for (e = cp; taglen && isspace(*cp); ++cp, --taglen);
+                if (taglen && (*cp == ':')) {
+                    tag = b;
+                    etag = e;
+                    p = cp + 1;
+                }
+            } else {
+                // what about <PRI>[<TIME>] <tag>_host '<tag><stuff>' : message
+                static const char host[] = "_host";
+                static const size_t hostlen = strlen(host);
+                if ((size > hostlen) &&
+                        !fast<strncmp>(bt + size - hostlen, host, hostlen) &&
+                        !fast<strncmp>(bt + 1, cp + 1, size - hostlen - 1)) {
                     const char *b = cp;
-                    cp += size - 5;
-                    taglen -= size - 5;
+                    cp += size - hostlen;
+                    taglen -= size - hostlen;
                     if (*cp == '.') {
                         while (--taglen && !isspace(*++cp) && (*cp != ':'));
                         const char *e;
-                        for(e = cp; taglen && isspace(*cp); ++cp, --taglen);
-                        if (*cp == ':') {
+                        for (e = cp; taglen && isspace(*cp); ++cp, --taglen);
+                        if (taglen && (*cp == ':')) {
                             tag = b;
                             etag = e;
                             p = cp + 1;
                         }
                     }
                 } else {
-                    while (--taglen && !isspace(*++cp) && (*cp != ':'));
-                    const char *e;
-                    for(e = cp; taglen && isspace(*cp); ++cp, --taglen);
-                    // Two words
-                    if (*cp == ':') {
-                        tag = bt;
-                        etag = e;
-                        p = cp + 1;
-                    }
-                }
-            } else if (isspace(cp[size])) {
-                cp += size;
-                taglen -= size;
-                while (--taglen && isspace(*++cp));
-                // <PRI>[<TIME>] <tag> <tag> : message
-                if (*cp == ':') {
-                    tag = bt;
-                    etag = et;
-                    p = cp + 1;
-                }
-            } else if (cp[size] == ':') {
-                // <PRI>[<TIME>] <tag> <tag> : message
-                tag = bt;
-                etag = et;
-                p = cp + size + 1;
-            } else if ((cp[size] == '.') || isdigit(cp[size])) {
-                // <PRI>[<TIME>] <tag> '<tag>.<num>' : message
-                // <PRI>[<TIME>] <tag> '<tag><num>' : message
-                const char *b = cp;
-                cp += size;
-                taglen -= size;
-                while (--taglen && !isspace(*++cp) && (*cp != ':'));
-                const char *e = cp;
-                while (taglen && isspace(*cp)) {
-                    ++cp;
-                    --taglen;
-                }
-                if (*cp == ':') {
-                    tag = b;
-                    etag = e;
-                    p = cp + 1;
-                }
-            } else {
-                while (--taglen && !isspace(*++cp) && (*cp != ':'));
-                const char *e = cp;
-                while (taglen && isspace(*cp)) {
-                    ++cp;
-                    --taglen;
-                }
-                // Two words
-                if (*cp == ':') {
-                    tag = bt;
-                    etag = e;
-                    p = cp + 1;
+                    goto twoWord;
                 }
             }
-        } /* else no tag */
-        size = etag - tag;
-        if ((size <= 1)
-            // register names like x9
-                || ((size == 2) && (isdigit(tag[0]) || isdigit(tag[1])))
-            // register names like x18 but not driver names like en0
-                || ((size == 3) && (isdigit(tag[1]) && isdigit(tag[2])))
-            // blacklist
-                || ((size == 3) && !fast<strncmp>(tag, "CPU", 3))
-                || ((size == 7) && !fast<strncasecmp>(tag, "WARNING", 7))
-                || ((size == 5) && !fast<strncasecmp>(tag, "ERROR", 5))
-                || ((size == 4) && !fast<strncasecmp>(tag, "INFO", 4))) {
-            p = start;
-            etag = tag = "";
+        } else {
+            // <PRI>[<TIME>] <tag> <stuff>' : message
+twoWord:    while (--taglen && !isspace(*++cp) && (*cp != ':'));
+            const char *e;
+            for (e = cp; taglen && isspace(*cp); ++cp, --taglen);
+            // Two words
+            if (taglen && (*cp == ':')) {
+                tag = bt;
+                etag = e;
+                p = cp + 1;
+            }
         }
+    } // else no tag
+
+    static const char cpu[] = "CPU";
+    static const size_t cpuLen = strlen(cpu);
+    static const char warning[] = "WARNING";
+    static const size_t warningLen = strlen(warning);
+    static const char error[] = "ERROR";
+    static const size_t errorLen = strlen(error);
+    static const char info[] = "INFO";
+    static const size_t infoLen = strlen(info);
+
+    size = etag - tag;
+    if ((size <= 1)
+        // register names like x9
+            || ((size == 2) && (isdigit(tag[0]) || isdigit(tag[1])))
+        // register names like x18 but not driver names like en0
+            || ((size == 3) && (isdigit(tag[1]) && isdigit(tag[2])))
+        // blacklist
+            || ((size == cpuLen) && !fast<strncmp>(tag, cpu, cpuLen))
+            || ((size == warningLen) && !fast<strncasecmp>(tag, warning, warningLen))
+            || ((size == errorLen) && !fast<strncasecmp>(tag, error, errorLen))
+            || ((size == infoLen) && !fast<strncasecmp>(tag, info, infoLen))) {
+        p = start;
+        etag = tag = "";
     }
+
     // Suppress additional stutter in tag:
     //   eg: [143:healthd]healthd -> [143:healthd]
     taglen = etag - tag;
diff --git a/rootdir/asan.options b/rootdir/asan.options
index 70e0eca..d728f12 100644
--- a/rootdir/asan.options
+++ b/rootdir/asan.options
@@ -3,4 +3,5 @@
 alloc_dealloc_mismatch=0
 allocator_may_return_null=1
 detect_container_overflow=0
+abort_on_error=1
 include_if_exists=/system/asan.options.%b
diff --git a/rootdir/init.usb.rc b/rootdir/init.usb.rc
index 1fd1e2a..915d159 100644
--- a/rootdir/init.usb.rc
+++ b/rootdir/init.usb.rc
@@ -103,7 +103,7 @@
 
 # Used to set USB configuration at boot and to switch the configuration
 # when changing the default configuration
-on property:persist.sys.usb.config=*
+on boot && property:persist.sys.usb.config=*
     setprop sys.usb.config ${persist.sys.usb.config}
 
 #