Merge "Adding a build id check to blob cache." into mnc-dev
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 0ce5ece..604bd57 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -45,11 +45,16 @@
 std::string escape_arg(const std::string& s) {
   std::string result = s;
 
-  // Insert a \ before any ' in the string.
-  for (auto it = result.begin(); it != result.end(); ++it) {
-      if (*it == '\'') {
-          it = result.insert(it, '\\') + 1;
-      }
+  // Escape any ' in the string (before we single-quote the whole thing).
+  // The correct way to do this for the shell is to replace ' with '\'' --- that is,
+  // close the existing single-quoted string, escape a single single-quote, and start
+  // a new single-quoted string. Like the C preprocessor, the shell will concatenate
+  // these pieces into one string.
+  for (size_t i = 0; i < s.size(); ++i) {
+    if (s[i] == '\'') {
+      result.insert(i, "'\\'");
+      i += 2;
+    }
   }
 
   // Prefix and suffix the whole string with '.
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index a395079..052aea5 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -30,21 +30,21 @@
   ASSERT_EQ(R"('abc')", escape_arg("abc"));
 
   ASSERT_EQ(R"(' abc')", escape_arg(" abc"));
-  ASSERT_EQ(R"('\'abc')", escape_arg("'abc"));
+  ASSERT_EQ(R"(''\''abc')", escape_arg("'abc"));
   ASSERT_EQ(R"('"abc')", escape_arg("\"abc"));
   ASSERT_EQ(R"('\abc')", escape_arg("\\abc"));
   ASSERT_EQ(R"('(abc')", escape_arg("(abc"));
   ASSERT_EQ(R"(')abc')", escape_arg(")abc"));
 
   ASSERT_EQ(R"('abc abc')", escape_arg("abc abc"));
-  ASSERT_EQ(R"('abc\'abc')", escape_arg("abc'abc"));
+  ASSERT_EQ(R"('abc'\''abc')", escape_arg("abc'abc"));
   ASSERT_EQ(R"('abc"abc')", escape_arg("abc\"abc"));
   ASSERT_EQ(R"('abc\abc')", escape_arg("abc\\abc"));
   ASSERT_EQ(R"('abc(abc')", escape_arg("abc(abc"));
   ASSERT_EQ(R"('abc)abc')", escape_arg("abc)abc"));
 
   ASSERT_EQ(R"('abc ')", escape_arg("abc "));
-  ASSERT_EQ(R"('abc\'')", escape_arg("abc'"));
+  ASSERT_EQ(R"('abc'\''')", escape_arg("abc'"));
   ASSERT_EQ(R"('abc"')", escape_arg("abc\""));
   ASSERT_EQ(R"('abc\')", escape_arg("abc\\"));
   ASSERT_EQ(R"('abc(')", escape_arg("abc("));
diff --git a/adb/tests/test_adb.py b/adb/tests/test_adb.py
index 237ef47..0ff87d2 100755
--- a/adb/tests/test_adb.py
+++ b/adb/tests/test_adb.py
@@ -6,6 +6,7 @@
 """
 import hashlib
 import os
+import pipes
 import random
 import re
 import shlex
@@ -162,6 +163,9 @@
     def shell_nocheck(self, cmd):
         return call_combined(self.adb_cmd + "shell " + cmd)
 
+    def install(self, filename):
+        return call_checked(self.adb_cmd + "install {}".format(pipes.quote(filename)))
+
     def push(self, local, remote):
         return call_checked(self.adb_cmd + "push {} {}".format(local, remote))
 
@@ -290,6 +294,18 @@
         self.assertEqual('t', adb.shell("FOO=a BAR=b echo t").strip())
         self.assertEqual('123Linux', adb.shell("echo -n 123\;uname").strip())
 
+    def test_install_argument_escaping(self):
+        """Make sure that install argument escaping works."""
+        adb = AdbWrapper()
+
+        # http://b/20323053
+        tf = tempfile.NamedTemporaryFile("w", suffix="-text;ls;1.apk")
+        self.assertIn("-text;ls;1.apk", adb.install(tf.name))
+
+        # http://b/3090932
+        tf = tempfile.NamedTemporaryFile("w", suffix="-Live Hold'em.apk")
+        self.assertIn("-Live Hold'em.apk", adb.install(tf.name))
+
 
 class AdbFile(unittest.TestCase):
     SCRATCH_DIR = "/data/local/tmp"
diff --git a/base/file.cpp b/base/file.cpp
index 6b19818..9a340b7 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -51,7 +51,7 @@
     return false;
   }
   bool result = ReadFdToString(fd, content);
-  TEMP_FAILURE_RETRY(close(fd));
+  close(fd);
   return result;
 }
 
@@ -102,7 +102,7 @@
     ALOGE("android::WriteStringToFile write failed: %s", strerror(errno));
     return CleanUpAfterFailedWrite(path);
   }
-  TEMP_FAILURE_RETRY(close(fd));
+  close(fd);
   return true;
 }
 #endif
@@ -116,7 +116,7 @@
   }
 
   bool result = WriteStringToFd(content, fd);
-  TEMP_FAILURE_RETRY(close(fd));
+  close(fd);
   return result || CleanUpAfterFailedWrite(path);
 }
 
diff --git a/debuggerd/backtrace.cpp b/debuggerd/backtrace.cpp
index c2a1dbc..b8084c5 100644
--- a/debuggerd/backtrace.cpp
+++ b/debuggerd/backtrace.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "DEBUG"
+
 #include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
@@ -26,8 +28,11 @@
 #include <sys/types.h>
 #include <sys/ptrace.h>
 
+#include <memory>
+
 #include <backtrace/Backtrace.h>
-#include <UniquePtr.h>
+
+#include <log/log.h>
 
 #include "backtrace.h"
 
@@ -92,9 +97,11 @@
     return;
   }
 
-  UniquePtr<Backtrace> backtrace(Backtrace::Create(tid, BACKTRACE_CURRENT_THREAD));
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(tid, BACKTRACE_CURRENT_THREAD));
   if (backtrace->Unwind(0)) {
     dump_backtrace_to_log(backtrace.get(), log, "  ");
+  } else {
+    ALOGE("Unwind failed: tid = %d", tid);
   }
 
   if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index b7e6b17..ccdfe85 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -32,6 +32,9 @@
 #include <sys/stat.h>
 #include <sys/un.h>
 
+#include <memory>
+#include <string>
+
 #include <private/android_filesystem_config.h>
 
 #include <base/stringprintf.h>
@@ -45,10 +48,6 @@
 
 #include <selinux/android.h>
 
-#include <UniquePtr.h>
-
-#include <string>
-
 #include "backtrace.h"
 #include "elf_utils.h"
 #include "machine.h"
@@ -445,9 +444,11 @@
     dump_thread_info(log, pid, new_tid);
 
     dump_registers(log, new_tid);
-    UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, new_tid, map));
+    std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, new_tid, map));
     if (backtrace->Unwind(0)) {
       dump_backtrace_and_stack(backtrace.get(), log);
+    } else {
+      ALOGE("Unwind of sibling failed: pid = %d, tid = %d", pid, new_tid);
     }
 
     log->current_tid = log->crashed_tid;
@@ -644,15 +645,19 @@
     dump_signal_info(log, tid, signal, si_code);
   }
 
-  UniquePtr<BacktraceMap> map(BacktraceMap::Create(pid));
-  UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
+  std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
   dump_abort_message(backtrace.get(), log, abort_msg_address);
   dump_registers(log, tid);
   if (backtrace->Unwind(0)) {
     dump_backtrace_and_stack(backtrace.get(), log);
+  } else {
+    ALOGE("Unwind failed: pid = %d, tid = %d", pid, tid);
   }
   dump_memory_and_code(log, tid);
-  dump_all_maps(backtrace.get(), map.get(), log, tid);
+  if (map.get() != nullptr) {
+    dump_all_maps(backtrace.get(), map.get(), log, tid);
+  }
 
   if (want_logs) {
     dump_logs(log, pid, 5);
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 7b2975b..0648826 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_MODULE := fastboot
 LOCAL_MODULE_TAGS := debug
 LOCAL_CONLYFLAGS += -std=gnu99
-LOCAL_CFLAGS += -Wall -Wextra -Werror
+LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
 
 ifeq ($(HOST_OS),linux)
   LOCAL_SRC_FILES += usb_linux.c util_linux.c
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index e35cc70..c599fc2 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -701,12 +701,14 @@
     ZipArchiveHandle zip;
     int error = OpenArchive(filename, &zip);
     if (error != 0) {
+        CloseArchive(zip);
         die("failed to open zip file '%s': %s", filename, ErrorCodeString(error));
     }
 
     unsigned sz;
     void* data = unzip_file(zip, "android-info.txt", &sz);
     if (data == 0) {
+        CloseArchive(zip);
         die("update package '%s' has no android-info.txt", filename);
     }
 
@@ -717,6 +719,7 @@
         if (fd < 0) {
             if (images[i].is_optional)
                 continue;
+            CloseArchive(zip);
             die("update package missing %s", images[i].img_name);
         }
         fastboot_buffer buf;
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index 1786e49..481c501 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -69,7 +69,7 @@
 /* util stuff */
 double now();
 char *mkmsg(const char *fmt, ...);
-void die(const char *fmt, ...);
+__attribute__((__noreturn__)) void die(const char *fmt, ...);
 
 void get_my_path(char *path);
 
diff --git a/fingerprintd/Android.mk b/fingerprintd/Android.mk
new file mode 100644
index 0000000..48b9525
--- /dev/null
+++ b/fingerprintd/Android.mk
@@ -0,0 +1,33 @@
+#
+# Copyright (C) 2015 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_CFLAGS := -Wall -Wextra -Werror -Wunused
+LOCAL_SRC_FILES := \
+	FingerprintDaemonProxy.cpp \
+	IFingerprintDaemon.cpp \
+	IFingerprintDaemonCallback.cpp \
+	fingerprintd.cpp
+LOCAL_MODULE := fingerprintd
+LOCAL_SHARED_LIBRARIES := \
+	libbinder \
+	liblog \
+	libhardware \
+	libutils \
+	libkeystore_binder
+include $(BUILD_EXECUTABLE)
diff --git a/fingerprintd/FingerprintDaemonProxy.cpp b/fingerprintd/FingerprintDaemonProxy.cpp
new file mode 100644
index 0000000..2091a2c
--- /dev/null
+++ b/fingerprintd/FingerprintDaemonProxy.cpp
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#define LOG_TAG "fingerprintd"
+
+#include <binder/IServiceManager.h>
+#include <hardware/hardware.h>
+#include <hardware/fingerprint.h>
+#include <hardware/hw_auth_token.h>
+#include <keystore/IKeystoreService.h>
+#include <keystore/keystore.h> // for error codes
+#include <utils/Log.h>
+
+#include "FingerprintDaemonProxy.h"
+
+namespace android {
+
+FingerprintDaemonProxy* FingerprintDaemonProxy::sInstance = NULL;
+
+// Supported fingerprint HAL version
+static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(2, 0);
+
+FingerprintDaemonProxy::FingerprintDaemonProxy() : mModule(NULL), mDevice(NULL), mCallback(NULL) {
+
+}
+
+FingerprintDaemonProxy::~FingerprintDaemonProxy() {
+    closeHal();
+}
+
+void FingerprintDaemonProxy::hal_notify_callback(fingerprint_msg_t msg) {
+    FingerprintDaemonProxy* instance = FingerprintDaemonProxy::getInstance();
+    const sp<IFingerprintDaemonCallback> callback = instance->mCallback;
+    if (callback == NULL) {
+        ALOGE("Invalid callback object");
+        return;
+    }
+    const int64_t device = (int64_t) instance->mDevice;
+    switch (msg.type) {
+        case FINGERPRINT_ERROR:
+            ALOGD("onError(%d)", msg.data.error);
+            callback->onError(device, msg.data.error);
+            break;
+        case FINGERPRINT_ACQUIRED:
+            ALOGD("onAcquired(%d)", msg.data.acquired.acquired_info);
+            callback->onAcquired(device, msg.data.acquired.acquired_info);
+            break;
+        case FINGERPRINT_AUTHENTICATED:
+            ALOGD("onAuthenticated(fid=%d, gid=%d)",
+                    msg.data.authenticated.finger.fid,
+                    msg.data.authenticated.finger.gid);
+            if (msg.data.authenticated.finger.fid != 0) {
+                uint8_t* hat = reinterpret_cast<uint8_t *>(&msg.data.authenticated.hat);
+                instance->notifyKeystore(hat, sizeof(msg.data.authenticated.hat));
+            }
+            callback->onAuthenticated(device,
+                    msg.data.authenticated.finger.fid,
+                    msg.data.authenticated.finger.gid);
+            break;
+        case FINGERPRINT_TEMPLATE_ENROLLING:
+            ALOGD("onEnrollResult(fid=%d, gid=%d, rem=%d)",
+                    msg.data.enroll.finger.fid,
+                    msg.data.enroll.finger.gid,
+                    msg.data.enroll.samples_remaining);
+            callback->onEnrollResult(device,
+                    msg.data.enroll.finger.fid,
+                    msg.data.enroll.finger.gid,
+                    msg.data.enroll.samples_remaining);
+            break;
+        case FINGERPRINT_TEMPLATE_REMOVED:
+            ALOGD("onRemove(fid=%d, gid=%d)",
+                    msg.data.removed.finger.fid,
+                    msg.data.removed.finger.gid);
+            callback->onRemoved(device,
+                    msg.data.removed.finger.fid,
+                    msg.data.removed.finger.gid);
+            break;
+        default:
+            ALOGE("invalid msg: %d", msg.type);
+            return;
+    }
+}
+
+void FingerprintDaemonProxy::notifyKeystore(uint8_t *auth_token, size_t auth_token_length) {
+    if (auth_token != NULL && auth_token_length > 0) {
+        // TODO: cache service?
+        sp < IServiceManager > sm = defaultServiceManager();
+        sp < IBinder > binder = sm->getService(String16("android.security.keystore"));
+        sp < IKeystoreService > service = interface_cast < IKeystoreService > (binder);
+        if (service != NULL) {
+            status_t ret = service->addAuthToken(auth_token, auth_token_length);
+            if (ret != ResponseCode::NO_ERROR) {
+                ALOGE("Falure sending auth token to KeyStore: %d", ret);
+            }
+        } else {
+            ALOGE("Unable to communicate with KeyStore");
+        }
+    }
+}
+
+void FingerprintDaemonProxy::init(const sp<IFingerprintDaemonCallback>& callback) {
+    if (mCallback != NULL && IInterface::asBinder(callback) != IInterface::asBinder(mCallback)) {
+        IInterface::asBinder(mCallback)->unlinkToDeath(this);
+    }
+    IInterface::asBinder(callback)->linkToDeath(this);
+    mCallback = callback;
+}
+
+int32_t FingerprintDaemonProxy::enroll(const uint8_t* token, ssize_t tokenSize, int32_t groupId,
+        int32_t timeout) {
+    ALOG(LOG_VERBOSE, LOG_TAG, "enroll(gid=%d, timeout=%d)\n", groupId, timeout);
+    if (tokenSize != sizeof(hw_auth_token_t) ) {
+        ALOG(LOG_VERBOSE, LOG_TAG, "enroll() : invalid token size %d\n", tokenSize);
+        return -1;
+    }
+    const hw_auth_token_t* authToken = reinterpret_cast<const hw_auth_token_t*>(token);
+    return mDevice->enroll(mDevice, authToken, groupId, timeout);
+}
+
+uint64_t FingerprintDaemonProxy::preEnroll() {
+    return mDevice->pre_enroll(mDevice);
+}
+
+int32_t FingerprintDaemonProxy::stopEnrollment() {
+    ALOG(LOG_VERBOSE, LOG_TAG, "stopEnrollment()\n");
+    return mDevice->cancel(mDevice);
+}
+
+int32_t FingerprintDaemonProxy::authenticate(uint64_t sessionId, uint32_t groupId) {
+    ALOG(LOG_VERBOSE, LOG_TAG, "authenticate(sid=%" PRId64 ", gid=%d)\n", sessionId, groupId);
+    return mDevice->authenticate(mDevice, sessionId, groupId);
+}
+
+int32_t FingerprintDaemonProxy::stopAuthentication() {
+    ALOG(LOG_VERBOSE, LOG_TAG, "stopAuthentication()\n");
+    return mDevice->cancel(mDevice);
+}
+
+int32_t FingerprintDaemonProxy::remove(int32_t fingerId, int32_t groupId) {
+    ALOG(LOG_VERBOSE, LOG_TAG, "remove(fid=%d, gid=%d)\n", fingerId, groupId);
+    fingerprint_finger_id_t finger;
+    finger.fid = fingerId;
+    finger.gid = groupId;
+    return mDevice->remove(mDevice, finger);
+}
+
+uint64_t FingerprintDaemonProxy::getAuthenticatorId() {
+    return mDevice->get_authenticator_id(mDevice);
+}
+
+int32_t FingerprintDaemonProxy::setActiveGroup(int32_t groupId, const uint8_t* path,
+        ssize_t pathlen) {
+    if (pathlen >= PATH_MAX) {
+        ALOGE("Path name is too long\n");
+        return -1;
+    }
+    // Convert to null-terminated string
+    char path_name[PATH_MAX];
+    memcpy(path_name, path, pathlen);
+    path_name[pathlen] = '\0';
+    ALOG(LOG_VERBOSE, LOG_TAG, "setActiveGroup(%d, %s, %d)", groupId, path_name, pathlen);
+    return mDevice->set_active_group(mDevice, groupId, path_name);
+    return -1;
+}
+
+int64_t FingerprintDaemonProxy::openHal() {
+    ALOG(LOG_VERBOSE, LOG_TAG, "nativeOpenHal()\n");
+    int err;
+    const hw_module_t *hw_module = NULL;
+    if (0 != (err = hw_get_module(FINGERPRINT_HARDWARE_MODULE_ID, &hw_module))) {
+        ALOGE("Can't open fingerprint HW Module, error: %d", err);
+        return 0;
+    }
+    if (NULL == hw_module) {
+        ALOGE("No valid fingerprint module");
+        return 0;
+    }
+
+    mModule = reinterpret_cast<const fingerprint_module_t*>(hw_module);
+
+    if (mModule->common.methods->open == NULL) {
+        ALOGE("No valid open method");
+        return 0;
+    }
+
+    hw_device_t *device = NULL;
+
+    if (0 != (err = mModule->common.methods->open(hw_module, NULL, &device))) {
+        ALOGE("Can't open fingerprint methods, error: %d", err);
+        return 0;
+    }
+
+    if (kVersion != device->version) {
+        ALOGE("Wrong fp version. Expected %d, got %d", kVersion, device->version);
+        // return 0; // FIXME
+    }
+
+    mDevice = reinterpret_cast<fingerprint_device_t*>(device);
+    err = mDevice->set_notify(mDevice, hal_notify_callback);
+    if (err < 0) {
+        ALOGE("Failed in call to set_notify(), err=%d", err);
+        return 0;
+    }
+
+    // Sanity check - remove
+    if (mDevice->notify != hal_notify_callback) {
+        ALOGE("NOTIFY not set properly: %p != %p", mDevice->notify, hal_notify_callback);
+    }
+
+    ALOG(LOG_VERBOSE, LOG_TAG, "fingerprint HAL successfully initialized");
+    return reinterpret_cast<int64_t>(mDevice); // This is just a handle
+}
+
+int32_t FingerprintDaemonProxy::closeHal() {
+    return -ENOSYS; // TODO
+}
+
+void FingerprintDaemonProxy::binderDied(const wp<IBinder>& who) {
+    ALOGD("binder died");
+    if (IInterface::asBinder(mCallback) == who) {
+        mCallback = NULL;
+    }
+}
+
+}
diff --git a/fingerprintd/FingerprintDaemonProxy.h b/fingerprintd/FingerprintDaemonProxy.h
new file mode 100644
index 0000000..95c926b
--- /dev/null
+++ b/fingerprintd/FingerprintDaemonProxy.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef FINGERPRINT_DAEMON_PROXY_H_
+#define FINGERPRINT_DAEMON_PROXY_H_
+
+#include "IFingerprintDaemon.h"
+#include "IFingerprintDaemonCallback.h"
+
+namespace android {
+
+class FingerprintDaemonProxy : public BnFingerprintDaemon {
+    public:
+        static FingerprintDaemonProxy* getInstance() {
+            if (sInstance == NULL) {
+                sInstance = new FingerprintDaemonProxy();
+            }
+            return sInstance;
+        }
+
+        // These reflect binder methods.
+        virtual void init(const sp<IFingerprintDaemonCallback>& callback);
+        virtual int32_t enroll(const uint8_t* token, ssize_t tokenLength, int32_t groupId, int32_t timeout);
+        virtual uint64_t preEnroll();
+        virtual int32_t stopEnrollment();
+        virtual int32_t authenticate(uint64_t sessionId, uint32_t groupId);
+        virtual int32_t stopAuthentication();
+        virtual int32_t remove(int32_t fingerId, int32_t groupId);
+        virtual uint64_t getAuthenticatorId();
+        virtual int32_t setActiveGroup(int32_t groupId, const uint8_t* path, ssize_t pathLen);
+        virtual int64_t openHal();
+        virtual int32_t closeHal();
+
+    private:
+        FingerprintDaemonProxy();
+        virtual ~FingerprintDaemonProxy();
+        void binderDied(const wp<IBinder>& who);
+        void notifyKeystore(uint8_t *auth_token, size_t auth_token_length);
+        static void hal_notify_callback(fingerprint_msg_t msg);
+
+        static FingerprintDaemonProxy* sInstance;
+        fingerprint_module_t const* mModule;
+        fingerprint_device_t* mDevice;
+        sp<IFingerprintDaemonCallback> mCallback;
+};
+
+} // namespace android
+
+#endif // FINGERPRINT_DAEMON_PROXY_H_
diff --git a/fingerprintd/IFingerprintDaemon.cpp b/fingerprintd/IFingerprintDaemon.cpp
new file mode 100644
index 0000000..5f9d30c
--- /dev/null
+++ b/fingerprintd/IFingerprintDaemon.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2015, 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 <inttypes.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/PermissionCache.h>
+#include <utils/String16.h>
+#include <utils/Looper.h>
+#include <keystore/IKeystoreService.h>
+#include <keystore/keystore.h> // for error code
+#include <hardware/hardware.h>
+#include <hardware/fingerprint.h>
+#include <hardware/hw_auth_token.h>
+#include "IFingerprintDaemon.h"
+#include "IFingerprintDaemonCallback.h"
+
+namespace android {
+
+static const String16 USE_FINGERPRINT_PERMISSION("android.permission.USE_FINGERPRINT");
+static const String16 MANAGE_FINGERPRINT_PERMISSION("android.permission.MANAGE_FINGERPRINT");
+static const String16 HAL_FINGERPRINT_PERMISSION("android.permission.MANAGE_FINGERPRINT"); // TODO
+static const String16 DUMP_PERMISSION("android.permission.DUMP");
+
+const android::String16
+IFingerprintDaemon::descriptor("android.hardware.fingerprint.IFingerprintDaemon");
+
+const android::String16&
+IFingerprintDaemon::getInterfaceDescriptor() const {
+    return IFingerprintDaemon::descriptor;
+}
+
+status_t BnFingerprintDaemon::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+        uint32_t flags) {
+    switch(code) {
+        case AUTHENTICATE: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            const uint64_t sessionId = data.readInt64();
+            const uint32_t groupId = data.readInt32();
+            const int32_t ret = authenticate(sessionId, groupId);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        };
+        case CANCEL_AUTHENTICATION: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            const int32_t ret = stopAuthentication();
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        }
+        case ENROLL: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            const ssize_t tokenSize = data.readInt32();
+            const uint8_t* token = static_cast<const uint8_t *>(data.readInplace(tokenSize));
+            const int32_t groupId = data.readInt32();
+            const int32_t timeout = data.readInt32();
+            const int32_t ret = enroll(token, tokenSize, groupId, timeout);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        }
+        case CANCEL_ENROLLMENT: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            const int32_t ret = stopEnrollment();
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        }
+        case PRE_ENROLL: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            const uint64_t ret = preEnroll();
+            reply->writeNoException();
+            reply->writeInt64(ret);
+            return NO_ERROR;
+        }
+        case REMOVE: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            const int32_t fingerId = data.readInt32();
+            const int32_t groupId = data.readInt32();
+            const int32_t ret = remove(fingerId, groupId);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        }
+        case GET_AUTHENTICATOR_ID: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            const uint64_t ret = getAuthenticatorId();
+            reply->writeNoException();
+            reply->writeInt64(ret);
+            return NO_ERROR;
+        }
+        case SET_ACTIVE_GROUP: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            const int32_t group = data.readInt32();
+            const ssize_t pathSize = data.readInt32();
+            const uint8_t* path = static_cast<const uint8_t *>(data.readInplace(pathSize));
+            const int32_t ret = setActiveGroup(group, path, pathSize);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        }
+        case OPEN_HAL: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            const int64_t ret = openHal();
+            reply->writeNoException();
+            reply->writeInt64(ret);
+            return NO_ERROR;
+        }
+        case CLOSE_HAL: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            const int32_t ret = closeHal();
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        }
+        case INIT: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            sp<IFingerprintDaemonCallback> callback =
+                    interface_cast<IFingerprintDaemonCallback>(data.readStrongBinder());
+            init(callback);
+            reply->writeNoException();
+            return NO_ERROR;
+        }
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+};
+
+bool BnFingerprintDaemon::checkPermission(const String16& permission) {
+    const IPCThreadState* ipc = IPCThreadState::self();
+    const int calling_pid = ipc->getCallingPid();
+    const int calling_uid = ipc->getCallingUid();
+    return PermissionCache::checkPermission(permission, calling_pid, calling_uid);
+}
+
+
+}; // namespace android
diff --git a/fingerprintd/IFingerprintDaemon.h b/fingerprintd/IFingerprintDaemon.h
new file mode 100644
index 0000000..fe3f64b
--- /dev/null
+++ b/fingerprintd/IFingerprintDaemon.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef IFINGERPRINT_DAEMON_H_
+#define IFINGERPRINT_DAEMON_H_
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+class IFingerprintDaemonCallback;
+
+/*
+* Abstract base class for native implementation of FingerprintService.
+*
+* Note: This must be kept manually in sync with IFingerprintDaemon.aidl
+*/
+class IFingerprintDaemon : public IInterface, public IBinder::DeathRecipient {
+    public:
+        enum {
+           AUTHENTICATE = IBinder::FIRST_CALL_TRANSACTION + 0,
+           CANCEL_AUTHENTICATION = IBinder::FIRST_CALL_TRANSACTION + 1,
+           ENROLL = IBinder::FIRST_CALL_TRANSACTION + 2,
+           CANCEL_ENROLLMENT = IBinder::FIRST_CALL_TRANSACTION + 3,
+           PRE_ENROLL = IBinder::FIRST_CALL_TRANSACTION + 4,
+           REMOVE = IBinder::FIRST_CALL_TRANSACTION + 5,
+           GET_AUTHENTICATOR_ID = IBinder::FIRST_CALL_TRANSACTION + 6,
+           SET_ACTIVE_GROUP = IBinder::FIRST_CALL_TRANSACTION + 7,
+           OPEN_HAL = IBinder::FIRST_CALL_TRANSACTION + 8,
+           CLOSE_HAL = IBinder::FIRST_CALL_TRANSACTION + 9,
+           INIT = IBinder::FIRST_CALL_TRANSACTION + 10,
+        };
+
+        IFingerprintDaemon() { }
+        virtual ~IFingerprintDaemon() { }
+        virtual const android::String16& getInterfaceDescriptor() const;
+
+        // Binder interface methods
+        virtual void init(const sp<IFingerprintDaemonCallback>& callback) = 0;
+        virtual int32_t enroll(const uint8_t* token, ssize_t tokenLength, int32_t groupId,
+                int32_t timeout) = 0;
+        virtual uint64_t preEnroll() = 0;
+        virtual int32_t stopEnrollment() = 0;
+        virtual int32_t authenticate(uint64_t sessionId, uint32_t groupId) = 0;
+        virtual int32_t stopAuthentication() = 0;
+        virtual int32_t remove(int32_t fingerId, int32_t groupId) = 0;
+        virtual uint64_t getAuthenticatorId() = 0;
+        virtual int32_t setActiveGroup(int32_t groupId, const uint8_t* path, ssize_t pathLen) = 0;
+        virtual int64_t openHal() = 0;
+        virtual int32_t closeHal() = 0;
+
+        // DECLARE_META_INTERFACE - C++ client interface not needed
+        static const android::String16 descriptor;
+        static void hal_notify_callback(fingerprint_msg_t msg);
+};
+
+// ----------------------------------------------------------------------------
+
+class BnFingerprintDaemon: public BnInterface<IFingerprintDaemon> {
+    public:
+       virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+               uint32_t flags = 0);
+    private:
+       bool checkPermission(const String16& permission);
+};
+
+} // namespace android
+
+#endif // IFINGERPRINT_DAEMON_H_
+
diff --git a/fingerprintd/IFingerprintDaemonCallback.cpp b/fingerprintd/IFingerprintDaemonCallback.cpp
new file mode 100644
index 0000000..44d8020
--- /dev/null
+++ b/fingerprintd/IFingerprintDaemonCallback.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#define LOG_TAG "IFingerprintDaemonCallback"
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+#include <binder/Parcel.h>
+
+#include "IFingerprintDaemonCallback.h"
+
+namespace android {
+
+class BpFingerprintDaemonCallback : public BpInterface<IFingerprintDaemonCallback>
+{
+public:
+    BpFingerprintDaemonCallback(const sp<IBinder>& impl) :
+            BpInterface<IFingerprintDaemonCallback>(impl) {
+    }
+    virtual status_t onEnrollResult(int64_t devId, int32_t fpId, int32_t gpId, int32_t rem) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor());
+        data.writeInt64(devId);
+        data.writeInt32(fpId);
+        data.writeInt32(gpId);
+        data.writeInt32(rem);
+        return remote()->transact(ON_ENROLL_RESULT, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual status_t onAcquired(int64_t devId, int32_t acquiredInfo) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor());
+        data.writeInt64(devId);
+        data.writeInt32(acquiredInfo);
+        return remote()->transact(ON_ACQUIRED, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual status_t onAuthenticated(int64_t devId, int32_t fpId, int32_t gpId) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor());
+        data.writeInt64(devId);
+        data.writeInt32(fpId);
+        data.writeInt32(gpId);
+        return remote()->transact(ON_AUTHENTICATED, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual status_t onError(int64_t devId, int32_t error) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor());
+        data.writeInt64(devId);
+        data.writeInt32(error);
+        return remote()->transact(ON_ERROR, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual status_t onRemoved(int64_t devId, int32_t fpId, int32_t gpId) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor());
+        data.writeInt64(devId);
+        data.writeInt32(fpId);
+        data.writeInt32(gpId);
+        return remote()->transact(ON_REMOVED, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual status_t onEnumerate(int64_t devId, const int32_t* fpIds, const int32_t* gpIds,
+            int32_t sz) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor());
+        data.writeInt64(devId);
+        data.writeInt32Array(sz, fpIds);
+        data.writeInt32Array(sz, gpIds);
+        return remote()->transact(ON_ENUMERATE, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(FingerprintDaemonCallback,
+        "android.hardware.fingerprint.IFingerprintDaemonCallback");
+
+}; // namespace android
diff --git a/fingerprintd/IFingerprintDaemonCallback.h b/fingerprintd/IFingerprintDaemonCallback.h
new file mode 100644
index 0000000..6e32213
--- /dev/null
+++ b/fingerprintd/IFingerprintDaemonCallback.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef IFINGERPRINT_DAEMON_CALLBACK_H_
+#define IFINGERPRINT_DAEMON_CALLBACK_H_
+
+#include <inttypes.h>
+#include <utils/Errors.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+/*
+* Communication channel back to FingerprintService.java
+*/
+class IFingerprintDaemonCallback : public IInterface {
+    public:
+        // must be kept in sync with IFingerprintService.aidl
+        enum {
+            ON_ENROLL_RESULT = IBinder::FIRST_CALL_TRANSACTION + 0,
+            ON_ACQUIRED = IBinder::FIRST_CALL_TRANSACTION + 1,
+            ON_AUTHENTICATED = IBinder::FIRST_CALL_TRANSACTION + 2,
+            ON_ERROR = IBinder::FIRST_CALL_TRANSACTION + 3,
+            ON_REMOVED = IBinder::FIRST_CALL_TRANSACTION + 4,
+            ON_ENUMERATE = IBinder::FIRST_CALL_TRANSACTION + 5,
+        };
+
+        virtual status_t onEnrollResult(int64_t devId, int32_t fpId, int32_t gpId, int32_t rem) = 0;
+        virtual status_t onAcquired(int64_t devId, int32_t acquiredInfo) = 0;
+        virtual status_t onAuthenticated(int64_t devId, int32_t fingerId, int32_t groupId) = 0;
+        virtual status_t onError(int64_t devId, int32_t error) = 0;
+        virtual status_t onRemoved(int64_t devId, int32_t fingerId, int32_t groupId) = 0;
+        virtual status_t onEnumerate(int64_t devId, const int32_t* fpIds, const int32_t* gpIds,
+                int32_t sz) = 0;
+
+        DECLARE_META_INTERFACE(FingerprintDaemonCallback);
+};
+
+}; // namespace android
+
+#endif // IFINGERPRINT_DAEMON_CALLBACK_H_
diff --git a/fingerprintd/fingerprintd.cpp b/fingerprintd/fingerprintd.cpp
new file mode 100644
index 0000000..8fa7ed1
--- /dev/null
+++ b/fingerprintd/fingerprintd.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#define LOG_TAG "fingerprintd"
+
+#include <cutils/log.h>
+#include <utils/Log.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/PermissionCache.h>
+#include <utils/String16.h>
+
+#include <keystore/IKeystoreService.h>
+#include <keystore/keystore.h> // for error codes
+
+#include <hardware/hardware.h>
+#include <hardware/fingerprint.h>
+#include <hardware/hw_auth_token.h>
+
+#include "FingerprintDaemonProxy.h"
+
+int main() {
+    ALOGI("Starting " LOG_TAG);
+    android::sp<android::IServiceManager> serviceManager = android::defaultServiceManager();
+    android::sp<android::FingerprintDaemonProxy> proxy =
+            android::FingerprintDaemonProxy::getInstance();
+    android::status_t ret = serviceManager->addService(
+            android::FingerprintDaemonProxy::descriptor, proxy);
+    if (ret != android::OK) {
+        ALOGE("Couldn't register " LOG_TAG " binder service!");
+        return -1;
+    }
+
+    /*
+     * We're the only thread in existence, so we're just going to process
+     * Binder transaction as a single-threaded program.
+     */
+    android::IPCThreadState::self()->joinThreadPool();
+    ALOGI("Done");
+    return 0;
+}
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index 882585c..f24af1f 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -15,10 +15,12 @@
  */
 
 #include <ctype.h>
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/mount.h>
+#include <unistd.h>
 
 #include "fs_mgr_priv.h"
 
@@ -76,6 +78,19 @@
     { 0,             0 },
 };
 
+static uint64_t calculate_zram_size(unsigned int percentage)
+{
+    uint64_t total;
+
+    total  = sysconf(_SC_PHYS_PAGES);
+    total *= percentage;
+    total /= 100;
+
+    total *= sysconf(_SC_PAGESIZE);
+
+    return total;
+}
+
 static int parse_flags(char *flags, struct flag_list *fl,
                        struct fs_mgr_flag_values *flag_vals,
                        char *fs_options, int fs_options_len)
@@ -157,7 +172,12 @@
                 } else if ((fl[i].flag == MF_SWAPPRIO) && flag_vals) {
                     flag_vals->swap_prio = strtoll(strchr(p, '=') + 1, NULL, 0);
                 } else if ((fl[i].flag == MF_ZRAMSIZE) && flag_vals) {
-                    flag_vals->zram_size = strtoll(strchr(p, '=') + 1, NULL, 0);
+                    int is_percent = !!strrchr(p, '%');
+                    unsigned int val = strtoll(strchr(p, '=') + 1, NULL, 0);
+                    if (is_percent)
+                        flag_vals->zram_size = calculate_zram_size(val);
+                    else
+                        flag_vals->zram_size = val;
                 }
                 break;
             }
diff --git a/gatekeeperd/Android.mk b/gatekeeperd/Android.mk
index f743cc3..be3d6fc 100644
--- a/gatekeeperd/Android.mk
+++ b/gatekeeperd/Android.mk
@@ -18,14 +18,16 @@
 
 include $(CLEAR_VARS)
 LOCAL_CFLAGS := -Wall -Wextra -Werror -Wunused
-LOCAL_SRC_FILES := IGateKeeperService.cpp gatekeeperd.cpp
+LOCAL_SRC_FILES := SoftGateKeeperDevice.cpp IGateKeeperService.cpp gatekeeperd.cpp
 LOCAL_MODULE := gatekeeperd
 LOCAL_SHARED_LIBRARIES := \
 	libbinder \
+	libgatekeeper \
 	liblog \
 	libhardware \
 	libutils \
+	libcrypto \
 	libkeystore_binder
-LOCAL_C_INCLUDES := \
-	system/gatekeeper/include
+LOCAL_STATIC_LIBRARIES := libscrypt_static
+LOCAL_C_INCLUDES := external/scrypt/lib/crypto
 include $(BUILD_EXECUTABLE)
diff --git a/gatekeeperd/SoftGateKeeperDevice.cpp b/gatekeeperd/SoftGateKeeperDevice.cpp
new file mode 100644
index 0000000..b96bf8d
--- /dev/null
+++ b/gatekeeperd/SoftGateKeeperDevice.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2015 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 <gatekeeper/soft_gatekeeper.h>
+
+#include "SoftGateKeeperDevice.h"
+
+namespace android {
+
+int SoftGateKeeperDevice::enroll(uint32_t uid,
+            const uint8_t *current_password_handle, uint32_t current_password_handle_length,
+            const uint8_t *current_password, uint32_t current_password_length,
+            const uint8_t *desired_password, uint32_t desired_password_length,
+            uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length) {
+
+    if (enrolled_password_handle == NULL || enrolled_password_handle_length == NULL ||
+            desired_password == NULL || desired_password_length == 0)
+        return -EINVAL;
+
+    // Current password and current password handle go together
+    if (current_password_handle == NULL || current_password_handle_length == 0 ||
+            current_password == NULL || current_password_length == 0) {
+        current_password_handle = NULL;
+        current_password_handle_length = 0;
+        current_password = NULL;
+        current_password_length = 0;
+    }
+
+    SizedBuffer desired_password_buffer(desired_password_length);
+    memcpy(desired_password_buffer.buffer.get(), desired_password, desired_password_length);
+
+    SizedBuffer current_password_handle_buffer(current_password_handle_length);
+    if (current_password_handle) {
+        memcpy(current_password_handle_buffer.buffer.get(), current_password_handle,
+                current_password_handle_length);
+    }
+
+    SizedBuffer current_password_buffer(current_password_length);
+    if (current_password) {
+        memcpy(current_password_buffer.buffer.get(), current_password, current_password_length);
+    }
+
+    EnrollRequest request(uid, &current_password_handle_buffer, &desired_password_buffer,
+            &current_password_buffer);
+    EnrollResponse response;
+
+    impl_->Enroll(request, &response);
+
+    if (response.error != ERROR_NONE)
+        return -EINVAL;
+
+    *enrolled_password_handle = response.enrolled_password_handle.buffer.release();
+    *enrolled_password_handle_length = response.enrolled_password_handle.length;
+    return 0;
+}
+
+int SoftGateKeeperDevice::verify(uint32_t uid,
+        uint64_t challenge, const uint8_t *enrolled_password_handle,
+        uint32_t enrolled_password_handle_length, const uint8_t *provided_password,
+        uint32_t provided_password_length, uint8_t **auth_token, uint32_t *auth_token_length) {
+
+    if (enrolled_password_handle == NULL ||
+            provided_password == NULL) {
+        return -EINVAL;
+    }
+
+    SizedBuffer password_handle_buffer(enrolled_password_handle_length);
+    memcpy(password_handle_buffer.buffer.get(), enrolled_password_handle,
+            enrolled_password_handle_length);
+    SizedBuffer provided_password_buffer(provided_password_length);
+    memcpy(provided_password_buffer.buffer.get(), provided_password, provided_password_length);
+
+    VerifyRequest request(uid, challenge, &password_handle_buffer, &provided_password_buffer);
+    VerifyResponse response;
+
+    impl_->Verify(request, &response);
+
+    if (response.error != ERROR_NONE)
+       return -EINVAL;
+
+    if (auth_token != NULL && auth_token_length != NULL) {
+       *auth_token = response.auth_token.buffer.release();
+       *auth_token_length = response.auth_token.length;
+    }
+
+    return 0;
+}
+} // namespace android
diff --git a/gatekeeperd/SoftGateKeeperDevice.h b/gatekeeperd/SoftGateKeeperDevice.h
new file mode 100644
index 0000000..c0b5047
--- /dev/null
+++ b/gatekeeperd/SoftGateKeeperDevice.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2015 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.
+ */
+
+#ifndef SOFT_GATEKEEPER_DEVICE_H_
+#define SOFT_GATEKEEPER_DEVICE_H_
+
+#include <gatekeeper/soft_gatekeeper.h>
+#include <UniquePtr.h>
+
+using namespace gatekeeper;
+
+namespace android {
+
+/**
+ * Software based GateKeeper implementation
+ */
+class SoftGateKeeperDevice {
+public:
+    SoftGateKeeperDevice() {
+        impl_.reset(new SoftGateKeeper());
+    }
+
+   // Wrappers to translate the gatekeeper HAL API to the Kegyuard Messages API.
+
+    /**
+     * Enrolls password_payload, which should be derived from a user selected pin or password,
+     * with the authentication factor private key used only for enrolling authentication
+     * factor data.
+     *
+     * Returns: 0 on success or an error code less than 0 on error.
+     * On error, enrolled_password_handle will not be allocated.
+     */
+    int enroll(uint32_t uid,
+            const uint8_t *current_password_handle, uint32_t current_password_handle_length,
+            const uint8_t *current_password, uint32_t current_password_length,
+            const uint8_t *desired_password, uint32_t desired_password_length,
+            uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length);
+
+    /**
+     * Verifies provided_password matches enrolled_password_handle.
+     *
+     * Implementations of this module may retain the result of this call
+     * to attest to the recency of authentication.
+     *
+     * On success, writes the address of a verification token to auth_token,
+     * usable to attest password verification to other trusted services. Clients
+     * may pass NULL for this value.
+     *
+     * Returns: 0 on success or an error code less than 0 on error
+     * On error, verification token will not be allocated
+     */
+    int verify(uint32_t uid, uint64_t challenge,
+            const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,
+            const uint8_t *provided_password, uint32_t provided_password_length,
+            uint8_t **auth_token, uint32_t *auth_token_length);
+private:
+    UniquePtr<GateKeeper> impl_;
+};
+
+} // namespace gatekeeper
+
+#endif //SOFT_GATEKEEPER_DEVICE_H_
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index 75cd225..72c7ba2 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -38,6 +38,8 @@
 #include <hardware/gatekeeper.h>
 #include <hardware/hw_auth_token.h>
 
+#include "SoftGateKeeperDevice.h"
+
 namespace android {
 
 static const String16 KEYGUARD_PERMISSION("android.permission.ACCESS_KEYGUARD_SECURE_STORAGE");
@@ -47,15 +49,18 @@
 public:
     GateKeeperProxy() {
         int ret = hw_get_module_by_class(GATEKEEPER_HARDWARE_MODULE_ID, NULL, &module);
-        if (ret < 0)
-            LOG_ALWAYS_FATAL_IF(ret < 0, "Unable to find GateKeeper HAL");
-        ret = gatekeeper_open(module, &device);
-        if (ret < 0)
-            LOG_ALWAYS_FATAL_IF(ret < 0, "Unable to open GateKeeper HAL");
+        if (ret < 0) {
+            ALOGW("falling back to software GateKeeper");
+            soft_device.reset(new SoftGateKeeperDevice());
+        } else {
+            ret = gatekeeper_open(module, &device);
+            if (ret < 0)
+                LOG_ALWAYS_FATAL_IF(ret < 0, "Unable to open GateKeeper HAL");
+        }
     }
 
     virtual ~GateKeeperProxy() {
-        gatekeeper_close(device);
+        if (device) gatekeeper_close(device);
     }
 
     void store_sid(uint32_t uid, uint64_t sid) {
@@ -111,11 +116,22 @@
 
         // need a desired password to enroll
         if (desired_password_length == 0) return -EINVAL;
-        int ret = device->enroll(device, uid,
-                current_password_handle, current_password_handle_length,
-                current_password, current_password_length,
-                desired_password, desired_password_length,
-                enrolled_password_handle, enrolled_password_handle_length);
+
+        int ret;
+        if (device) {
+            ret = device->enroll(device, uid,
+                    current_password_handle, current_password_handle_length,
+                    current_password, current_password_length,
+                    desired_password, desired_password_length,
+                    enrolled_password_handle, enrolled_password_handle_length);
+        } else {
+            ret = soft_device->enroll(uid,
+                    current_password_handle, current_password_handle_length,
+                    current_password, current_password_length,
+                    desired_password, desired_password_length,
+                    enrolled_password_handle, enrolled_password_handle_length);
+        }
+
         if (ret >= 0) {
             gatekeeper::password_handle_t *handle =
                     reinterpret_cast<gatekeeper::password_handle_t *>(*enrolled_password_handle);
@@ -150,9 +166,16 @@
         if ((enrolled_password_handle_length | provided_password_length) == 0)
             return -EINVAL;
 
-        int ret = device->verify(device, uid, challenge,
+        int ret;
+        if (device) {
+            ret = device->verify(device, uid, challenge,
                 enrolled_password_handle, enrolled_password_handle_length,
                 provided_password, provided_password_length, auth_token, auth_token_length);
+        } else {
+            ret = soft_device->verify(uid, challenge,
+                enrolled_password_handle, enrolled_password_handle_length,
+                provided_password, provided_password_length, auth_token, auth_token_length);
+        }
 
         if (ret >= 0 && *auth_token != NULL && *auth_token_length > 0) {
             // TODO: cache service?
@@ -214,6 +237,7 @@
 
 private:
     gatekeeper_device_t *device;
+    UniquePtr<SoftGateKeeperDevice> soft_device;
     const hw_module_t *module;
 };
 }// namespace android
diff --git a/include/cutils/threads.h b/include/cutils/threads.h
index 3133cdb..5727494 100644
--- a/include/cutils/threads.h
+++ b/include/cutils/threads.h
@@ -17,6 +17,14 @@
 #ifndef _LIBS_CUTILS_THREADS_H
 #define _LIBS_CUTILS_THREADS_H
 
+#include  <sys/types.h>
+
+#if !defined(_WIN32)
+#include <pthread.h>
+#else
+#include <windows.h>
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -29,10 +37,9 @@
 /***********************************************************************/
 /***********************************************************************/
 
-#if !defined(_WIN32)
+extern pid_t gettid();
 
-#include  <pthread.h>
-#include  <sys/types.h>
+#if !defined(_WIN32)
 
 typedef struct {
     pthread_mutex_t   lock;
@@ -40,14 +47,10 @@
     pthread_key_t     tls;
 } thread_store_t;
 
-extern pid_t gettid();
-
 #define  THREAD_STORE_INITIALIZER  { PTHREAD_MUTEX_INITIALIZER, 0, 0 }
 
 #else // !defined(_WIN32)
 
-#include <windows.h>
-
 typedef struct {
     int               lock_init;
     int               has_tls;
diff --git a/include/log/log.h b/include/log/log.h
index f9299b0..0b17574 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -598,6 +598,7 @@
     LOG_ID_EVENTS = 2,
     LOG_ID_SYSTEM = 3,
     LOG_ID_CRASH = 4,
+    LOG_ID_KERNEL = 5,
 #endif
 
     LOG_ID_MAX
diff --git a/include/log/logprint.h b/include/log/logprint.h
index 1e42b47..96249e9 100644
--- a/include/log/logprint.h
+++ b/include/log/logprint.h
@@ -36,7 +36,9 @@
     FORMAT_TIME,
     FORMAT_THREADTIME,
     FORMAT_LONG,
-    FORMAT_COLOR,
+    /* The following two are modifiers to above formats */
+    FORMAT_MODIFIER_COLOR,     /* converts priority to color */
+    FORMAT_MODIFIER_TIME_USEC, /* switches from msec to usec time precision */
 } AndroidLogPrintFormat;
 
 typedef struct AndroidLogFormat_t AndroidLogFormat;
@@ -56,7 +58,8 @@
 
 void android_log_format_free(AndroidLogFormat *p_format);
 
-void android_log_setPrintFormat(AndroidLogFormat *p_format, 
+/* currently returns 0 if format is a modifier, 1 if not */
+int android_log_setPrintFormat(AndroidLogFormat *p_format,
         AndroidLogPrintFormat format);
 
 /**
@@ -64,7 +67,7 @@
  */
 AndroidLogPrintFormat android_log_formatFromString(const char *s);
 
-/** 
+/**
  * filterExpression: a single filter expression
  * eg "AT:d"
  *
@@ -74,12 +77,12 @@
  *
  */
 
-int android_log_addFilterRule(AndroidLogFormat *p_format, 
+int android_log_addFilterRule(AndroidLogFormat *p_format,
         const char *filterExpression);
 
 
-/** 
- * filterString: a whitespace-separated set of filter expressions 
+/**
+ * filterString: a whitespace-separated set of filter expressions
  * eg "AT:d *:i"
  *
  * returns 0 on success and -1 on invalid expression
@@ -92,7 +95,7 @@
         const char *filterString);
 
 
-/** 
+/**
  * returns 1 if this log line should be printed based on its priority
  * and tag, and 0 if it should not
  */
@@ -129,7 +132,7 @@
  * Returns NULL on malloc error
  */
 
-char *android_log_formatLogLine (    
+char *android_log_formatLogLine (
     AndroidLogFormat *p_format,
     char *defaultBuffer,
     size_t defaultBufferSize,
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 4567b04..735033e 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -57,8 +57,14 @@
 
 static int insmod(const char *filename, char *options)
 {
+    char filename_val[PROP_VALUE_MAX];
+    if (expand_props(filename_val, filename, sizeof(filename_val)) == -1) {
+        ERROR("insmod: cannot expand '%s'\n", filename);
+        return -EINVAL;
+    }
+
     std::string module;
-    if (!read_file(filename, &module)) {
+    if (!read_file(filename_val, &module)) {
         return -1;
     }
 
diff --git a/init/init.cpp b/init/init.cpp
index dd74538..5185f77 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -618,7 +618,10 @@
     Timer t;
 
     NOTICE("Waiting for %s...\n", COLDBOOT_DONE);
-    if (wait_for_file(COLDBOOT_DONE, COMMAND_RETRY_TIMEOUT)) {
+    // Any longer than 1s is an unreasonable length of time to delay booting.
+    // If you're hitting this timeout, check that you didn't make your
+    // sepolicy regular expressions too expensive (http://b/19899875).
+    if (wait_for_file(COLDBOOT_DONE, 1)) {
         ERROR("Timed out waiting for %s\n", COLDBOOT_DONE);
     }
 
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index b76b04e..d36995d 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -382,13 +382,13 @@
 
 static void parse_config(const char *fn, const std::string& data)
 {
-    struct parse_state state;
     struct listnode import_list;
     struct listnode *node;
     char *args[INIT_PARSER_MAXARGS];
-    int nargs;
 
-    nargs = 0;
+    int nargs = 0;
+
+    parse_state state;
     state.filename = fn;
     state.line = 0;
     state.ptr = strdup(data.c_str());  // TODO: fix this code!
@@ -444,6 +444,7 @@
         return -1;
     }
 
+    data.push_back('\n'); // TODO: fix parse_config.
     parse_config(path, data);
     dump_parser_state();
 
diff --git a/init/property_service.cpp b/init/property_service.cpp
index a52c41d..0ee0351 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -420,6 +420,7 @@
     Timer t;
     std::string data;
     if (read_file(filename, &data)) {
+        data.push_back('\n');
         load_properties(&data[0], filter);
     }
     NOTICE("(Loading properties from %s took %.2fs.)\n", filename, t.duration());
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index 7a4841f..497c606 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -193,10 +193,10 @@
 
 static void parse_config(const char *fn, const std::string& data)
 {
-    struct parse_state state;
     char *args[UEVENTD_PARSER_MAXARGS];
-    int nargs;
-    nargs = 0;
+
+    int nargs = 0;
+    parse_state state;
     state.filename = fn;
     state.line = 1;
     state.ptr = strdup(data.c_str());  // TODO: fix this code!
@@ -231,6 +231,7 @@
         return -1;
     }
 
+    data.push_back('\n'); // TODO: fix parse_config.
     parse_config(fn, data);
     dump_parser_state();
     return 0;
diff --git a/init/util.cpp b/init/util.cpp
index d6fd0fc..b3947f7 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -171,9 +171,6 @@
 
     bool okay = android::base::ReadFdToString(fd, content);
     TEMP_FAILURE_RETRY(close(fd));
-    if (okay) {
-        content->append("\n", 1);
-    }
     return okay;
 }
 
@@ -369,10 +366,10 @@
 int wait_for_file(const char *filename, int timeout)
 {
     struct stat info;
-    time_t timeout_time = gettime() + timeout;
+    uint64_t timeout_time_ns = gettime_ns() + timeout * UINT64_C(1000000000);
     int ret = -1;
 
-    while (gettime() < timeout_time && ((ret = stat(filename, &info)) < 0))
+    while (gettime_ns() < timeout_time_ns && ((ret = stat(filename, &info)) < 0))
         usleep(10000);
 
     return ret;
@@ -475,4 +472,3 @@
         android::base::StringAppendF(&hex, "%02x", bytes[i]);
     return hex;
 }
-
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index 54cace9..6a689a6 100644
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -118,12 +118,14 @@
 backtrace_test_shared_libraries := \
 	libbacktrace_test \
 	libbacktrace \
-
-backtrace_test_shared_libraries_target := \
+	libbase \
 	libcutils \
 
-backtrace_test_static_libraries_host := \
-	libcutils \
+backtrace_test_shared_libraries_target += \
+	libdl \
+
+backtrace_test_ldlibs_host += \
+	-ldl \
 
 module := backtrace_test
 module_tag := debug
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index d75c210..128bb04 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -27,6 +27,8 @@
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 
+#include <cutils/threads.h>
+
 #include "BacktraceLog.h"
 #include "thread_utils.h"
 #include "UnwindCurrent.h"
@@ -112,7 +114,9 @@
 }
 
 void Backtrace::FillInMap(uintptr_t pc, backtrace_map_t* map) {
-  map_->FillIn(pc, map);
+  if (map_ != nullptr) {
+    map_->FillIn(pc, map);
+  }
 }
 
 Backtrace* Backtrace::Create(pid_t pid, pid_t tid, BacktraceMap* map) {
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
index fd1f4da..95cd4d1 100644
--- a/libbacktrace/BacktraceCurrent.cpp
+++ b/libbacktrace/BacktraceCurrent.cpp
@@ -29,6 +29,8 @@
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 
+#include <cutils/threads.h>
+
 #include "BacktraceCurrent.h"
 #include "BacktraceLog.h"
 #include "ThreadEntry.h"
@@ -63,6 +65,11 @@
 }
 
 bool BacktraceCurrent::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
+  if (GetMap() == nullptr) {
+    // Without a map object, we can't do anything.
+    return false;
+  }
+
   if (ucontext) {
     return UnwindFromContext(num_ignore_frames, ucontext);
   }
diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp
index a7c3de5..07c2430 100644
--- a/libbacktrace/UnwindPtrace.cpp
+++ b/libbacktrace/UnwindPtrace.cpp
@@ -48,6 +48,11 @@
 }
 
 bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
+  if (GetMap() == nullptr) {
+    // Without a map object, we can't do anything.
+    return false;
+  }
+
   if (ucontext) {
     BACK_LOGW("Unwinding from a specified context not supported yet.");
     return false;
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index ba3cbb5..760f5cc 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -16,7 +16,9 @@
 
 #define _GNU_SOURCE 1
 #include <dirent.h>
+#include <dlfcn.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <inttypes.h>
 #include <pthread.h>
 #include <signal.h>
@@ -25,25 +27,29 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/ptrace.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <time.h>
 #include <unistd.h>
 
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-
-// For the THREAD_SIGNAL definition.
-#include "BacktraceCurrent.h"
-
-#include <cutils/atomic.h>
-#include <gtest/gtest.h>
-
 #include <algorithm>
+#include <list>
 #include <memory>
 #include <string>
 #include <vector>
 
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+
+#include <base/stringprintf.h>
+#include <cutils/atomic.h>
+#include <cutils/threads.h>
+
+#include <gtest/gtest.h>
+
+// For the THREAD_SIGNAL definition.
+#include "BacktraceCurrent.h"
 #include "thread_utils.h"
 
 // Number of microseconds per milliseconds.
@@ -1022,6 +1028,7 @@
 }
 
 TEST(libbacktrace, process_read) {
+  g_ready = 0;
   pid_t pid;
   if ((pid = fork()) == 0) {
     ForkedReadTest();
@@ -1068,6 +1075,297 @@
   ASSERT_TRUE(test_executed);
 }
 
+void VerifyFunctionsFound(const std::vector<std::string>& found_functions) {
+  // We expect to find these functions in libbacktrace_test. If we don't
+  // find them, that's a bug in the memory read handling code in libunwind.
+  std::list<std::string> expected_functions;
+  expected_functions.push_back("test_recursive_call");
+  expected_functions.push_back("test_level_one");
+  expected_functions.push_back("test_level_two");
+  expected_functions.push_back("test_level_three");
+  expected_functions.push_back("test_level_four");
+  for (const auto& found_function : found_functions) {
+    for (const auto& expected_function : expected_functions) {
+      if (found_function == expected_function) {
+        expected_functions.remove(found_function);
+        break;
+      }
+    }
+  }
+  ASSERT_TRUE(expected_functions.empty()) << "Not all functions found in shared library.";
+}
+
+const char* CopySharedLibrary() {
+#if defined(__LP64__)
+  const char* lib_name = "lib64";
+#else
+  const char* lib_name = "lib";
+#endif
+
+#if defined(__BIONIC__)
+  const char* tmp_so_name = "/data/local/tmp/libbacktrace_test.so";
+  std::string cp_cmd = android::base::StringPrintf("cp /system/%s/libbacktrace_test.so %s",
+                                                   lib_name, tmp_so_name);
+#else
+  const char* tmp_so_name = "/tmp/libbacktrace_test.so";
+  if (getenv("ANDROID_HOST_OUT") == NULL) {
+    fprintf(stderr, "ANDROID_HOST_OUT not set, make sure you run lunch.");
+    return nullptr;
+  }
+  std::string cp_cmd = android::base::StringPrintf("cp %s/%s/libbacktrace_test.so %s",
+                                                   getenv("ANDROID_HOST_OUT"), lib_name,
+                                                   tmp_so_name);
+#endif
+
+  // Copy the shared so to a tempory directory.
+  system(cp_cmd.c_str());
+
+  return tmp_so_name;
+}
+
+TEST(libbacktrace, check_unreadable_elf_local) {
+  const char* tmp_so_name = CopySharedLibrary();
+  ASSERT_TRUE(tmp_so_name != nullptr);
+
+  struct stat buf;
+  ASSERT_TRUE(stat(tmp_so_name, &buf) != -1);
+  uintptr_t map_size = buf.st_size;
+
+  int fd = open(tmp_so_name, O_RDONLY);
+  ASSERT_TRUE(fd != -1);
+
+  void* map = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE, fd, 0);
+  ASSERT_TRUE(map != MAP_FAILED);
+  close(fd);
+  ASSERT_TRUE(unlink(tmp_so_name) != -1);
+
+  std::vector<std::string> found_functions;
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS,
+                                                         BACKTRACE_CURRENT_THREAD));
+  ASSERT_TRUE(backtrace.get() != nullptr);
+
+  // Needed before GetFunctionName will work.
+  backtrace->Unwind(0);
+
+  // Loop through the entire map, and get every function we can find.
+  map_size += reinterpret_cast<uintptr_t>(map);
+  std::string last_func;
+  for (uintptr_t read_addr = reinterpret_cast<uintptr_t>(map);
+       read_addr < map_size; read_addr += 4) {
+    uintptr_t offset;
+    std::string func_name = backtrace->GetFunctionName(read_addr, &offset);
+    if (!func_name.empty() && last_func != func_name) {
+      found_functions.push_back(func_name);
+    }
+    last_func = func_name;
+  }
+
+  ASSERT_TRUE(munmap(map, map_size - reinterpret_cast<uintptr_t>(map)) == 0);
+
+  VerifyFunctionsFound(found_functions);
+}
+
+TEST(libbacktrace, check_unreadable_elf_remote) {
+  const char* tmp_so_name = CopySharedLibrary();
+  ASSERT_TRUE(tmp_so_name != nullptr);
+
+  g_ready = 0;
+
+  struct stat buf;
+  ASSERT_TRUE(stat(tmp_so_name, &buf) != -1);
+  uintptr_t map_size = buf.st_size;
+
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    int fd = open(tmp_so_name, O_RDONLY);
+    if (fd == -1) {
+      fprintf(stderr, "Failed to open file %s: %s\n", tmp_so_name, strerror(errno));
+      unlink(tmp_so_name);
+      exit(0);
+    }
+
+    void* map = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE, fd, 0);
+    if (map == MAP_FAILED) {
+      fprintf(stderr, "Failed to map in memory: %s\n", strerror(errno));
+      unlink(tmp_so_name);
+      exit(0);
+    }
+    close(fd);
+    if (unlink(tmp_so_name) == -1) {
+      fprintf(stderr, "Failed to unlink: %s\n", strerror(errno));
+      exit(0);
+    }
+
+    g_addr = reinterpret_cast<uintptr_t>(map);
+    g_ready = 1;
+    while (true) {
+      usleep(US_PER_MSEC);
+    }
+    exit(0);
+  }
+  ASSERT_TRUE(pid > 0);
+
+  std::vector<std::string> found_functions;
+  uint64_t start = NanoTime();
+  while (true) {
+    ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
+
+    // Wait for the process to get to a stopping point.
+    WaitForStop(pid);
+
+    std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
+    ASSERT_TRUE(backtrace.get() != nullptr);
+
+    uintptr_t read_addr;
+    ASSERT_EQ(sizeof(uintptr_t), backtrace->Read(reinterpret_cast<uintptr_t>(&g_ready), reinterpret_cast<uint8_t*>(&read_addr), sizeof(uintptr_t)));
+    if (read_addr) {
+      ASSERT_EQ(sizeof(uintptr_t), backtrace->Read(reinterpret_cast<uintptr_t>(&g_addr), reinterpret_cast<uint8_t*>(&read_addr), sizeof(uintptr_t)));
+
+      // Needed before GetFunctionName will work.
+      backtrace->Unwind(0);
+
+      // Loop through the entire map, and get every function we can find.
+      map_size += read_addr;
+      std::string last_func;
+      for (; read_addr < map_size; read_addr += 4) {
+        uintptr_t offset;
+        std::string func_name = backtrace->GetFunctionName(read_addr, &offset);
+        if (!func_name.empty() && last_func != func_name) {
+          found_functions.push_back(func_name);
+        }
+        last_func = func_name;
+      }
+      break;
+    }
+    ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
+
+    if ((NanoTime() - start) > 5 * NS_PER_SEC) {
+      break;
+    }
+    usleep(US_PER_MSEC);
+  }
+
+  kill(pid, SIGKILL);
+  ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
+
+  VerifyFunctionsFound(found_functions);
+}
+
+bool FindFuncFrameInBacktrace(Backtrace* backtrace, uintptr_t test_func, size_t* frame_num) {
+  backtrace_map_t map;
+  backtrace->FillInMap(test_func, &map);
+  if (!BacktraceMap::IsValid(map)) {
+    return false;
+  }
+
+  // Loop through the frames, and find the one that is in the map.
+  *frame_num = 0;
+  for (Backtrace::const_iterator it = backtrace->begin(); it != backtrace->end(); ++it) {
+    if (BacktraceMap::IsValid(it->map) && map.start == it->map.start &&
+        it->pc >= test_func) {
+      *frame_num = it->num;
+      return true;
+    }
+  }
+  return false;
+}
+
+void VerifyUnreadableElfFrame(Backtrace* backtrace, uintptr_t test_func, size_t frame_num) {
+  ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES))
+    << DumpFrames(backtrace);
+
+  ASSERT_TRUE(frame_num != 0) << DumpFrames(backtrace);
+  // Make sure that there is at least one more frame above the test func call.
+  ASSERT_LT(frame_num, backtrace->NumFrames()) << DumpFrames(backtrace);
+
+  uintptr_t diff = backtrace->GetFrame(frame_num)->pc - test_func;
+  ASSERT_LT(diff, 200U) << DumpFrames(backtrace);
+}
+
+void VerifyUnreadableElfBacktrace(uintptr_t test_func) {
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS,
+                                                         BACKTRACE_CURRENT_THREAD));
+  ASSERT_TRUE(backtrace.get() != nullptr);
+  ASSERT_TRUE(backtrace->Unwind(0));
+
+  size_t frame_num;
+  ASSERT_TRUE(FindFuncFrameInBacktrace(backtrace.get(), test_func, &frame_num));
+
+  VerifyUnreadableElfFrame(backtrace.get(), test_func, frame_num);
+}
+
+typedef int (*test_func_t)(int, int, int, int, void (*)(uintptr_t), uintptr_t);
+
+TEST(libbacktrace, unwind_through_unreadable_elf_local) {
+  const char* tmp_so_name = CopySharedLibrary();
+  ASSERT_TRUE(tmp_so_name != nullptr);
+  void* lib_handle = dlopen(tmp_so_name, RTLD_NOW);
+  ASSERT_TRUE(lib_handle != nullptr);
+  ASSERT_TRUE(unlink(tmp_so_name) != -1);
+
+  test_func_t test_func;
+  test_func = reinterpret_cast<test_func_t>(dlsym(lib_handle, "test_level_one"));
+  ASSERT_TRUE(test_func != nullptr);
+
+  ASSERT_NE(test_func(1, 2, 3, 4, VerifyUnreadableElfBacktrace,
+                      reinterpret_cast<uintptr_t>(test_func)), 0);
+
+  ASSERT_TRUE(dlclose(lib_handle) == 0);
+}
+
+TEST(libbacktrace, unwind_through_unreadable_elf_remote) {
+  const char* tmp_so_name = CopySharedLibrary();
+  ASSERT_TRUE(tmp_so_name != nullptr);
+  void* lib_handle = dlopen(tmp_so_name, RTLD_NOW);
+  ASSERT_TRUE(lib_handle != nullptr);
+  ASSERT_TRUE(unlink(tmp_so_name) != -1);
+
+  test_func_t test_func;
+  test_func = reinterpret_cast<test_func_t>(dlsym(lib_handle, "test_level_one"));
+  ASSERT_TRUE(test_func != nullptr);
+
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    test_func(1, 2, 3, 4, 0, 0);
+    exit(0);
+  }
+  ASSERT_TRUE(pid > 0);
+  ASSERT_TRUE(dlclose(lib_handle) == 0);
+
+  uint64_t start = NanoTime();
+  bool done = false;
+  while (!done) {
+    ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
+
+    // Wait for the process to get to a stopping point.
+    WaitForStop(pid);
+
+    std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
+    ASSERT_TRUE(backtrace.get() != nullptr);
+    ASSERT_TRUE(backtrace->Unwind(0));
+
+    size_t frame_num;
+    if (FindFuncFrameInBacktrace(backtrace.get(),
+                                 reinterpret_cast<uintptr_t>(test_func), &frame_num)) {
+
+      VerifyUnreadableElfFrame(backtrace.get(), reinterpret_cast<uintptr_t>(test_func), frame_num);
+      done = true;
+    }
+
+    ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
+
+    if ((NanoTime() - start) > 5 * NS_PER_SEC) {
+      break;
+    }
+    usleep(US_PER_MSEC);
+  }
+
+  kill(pid, SIGKILL);
+  ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
+
+  ASSERT_TRUE(done) << "Test function never found in unwind.";
+}
+
 #if defined(ENABLE_PSS_TESTS)
 #include "GetPss.h"
 
@@ -1141,3 +1439,4 @@
   ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
 }
 #endif
+
diff --git a/libbacktrace/thread_utils.c b/libbacktrace/thread_utils.c
index 6f4cd3c..e75f56e 100644
--- a/libbacktrace/thread_utils.c
+++ b/libbacktrace/thread_utils.c
@@ -16,25 +16,12 @@
 
 #include "thread_utils.h"
 
-#if defined(__APPLE__)
+#if !defined(__BIONIC__)
 
-#include <sys/syscall.h>
-
-// Mac OS >= 10.6 has a system call equivalent to Linux's gettid().
-pid_t gettid() {
-  return syscall(SYS_thread_selfid);
-}
-
-#elif !defined(__BIONIC__)
-
-// glibc doesn't implement or export either gettid or tgkill.
+// glibc doesn't implement or export tgkill.
 #include <unistd.h>
 #include <sys/syscall.h>
 
-pid_t gettid() {
-  return syscall(__NR_gettid);
-}
-
 int tgkill(int tgid, int tid, int sig) {
   return syscall(__NR_tgkill, tgid, tid, sig);
 }
diff --git a/libbacktrace/thread_utils.h b/libbacktrace/thread_utils.h
index ae4c929..df83581 100644
--- a/libbacktrace/thread_utils.h
+++ b/libbacktrace/thread_utils.h
@@ -23,8 +23,6 @@
 
 int tgkill(int tgid, int tid, int sig);
 
-pid_t gettid();
-
 __END_DECLS
 
 #endif /* _LIBBACKTRACE_THREAD_UTILS_H */
diff --git a/libcutils/klog.c b/libcutils/klog.c
index f574f08..710dc66 100644
--- a/libcutils/klog.c
+++ b/libcutils/klog.c
@@ -40,6 +40,11 @@
 void klog_init(void) {
     if (klog_fd >= 0) return; /* Already initialized */
 
+    klog_fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
+    if (klog_fd >= 0) {
+        return;
+    }
+
     static const char* name = "/dev/__kmsg__";
     if (mknod(name, S_IFCHR | 0600, (1 << 8) | 11) == 0) {
         klog_fd = open(name, O_WRONLY | O_CLOEXEC);
diff --git a/libcutils/native_handle.c b/libcutils/native_handle.c
index 9a4a5bb..61fa38e 100644
--- a/libcutils/native_handle.c
+++ b/libcutils/native_handle.c
@@ -25,11 +25,17 @@
 #include <cutils/log.h>
 #include <cutils/native_handle.h>
 
+static const int kMaxNativeFds = 1024;
+static const int kMaxNativeInts = 1024;
+
 native_handle_t* native_handle_create(int numFds, int numInts)
 {
-    native_handle_t* h = malloc(
-            sizeof(native_handle_t) + sizeof(int)*(numFds+numInts));
+    if (numFds < 0 || numInts < 0 || numFds > kMaxNativeFds || numInts > kMaxNativeInts) {
+        return NULL;
+    }
 
+    size_t mallocSize = sizeof(native_handle_t) + (sizeof(int) * (numFds + numInts));
+    native_handle_t* h = malloc(mallocSize);
     if (h) {
         h->version = sizeof(native_handle_t);
         h->numFds = numFds;
diff --git a/libcutils/threads.c b/libcutils/threads.c
index 5f5577b..036f8c5 100644
--- a/libcutils/threads.c
+++ b/libcutils/threads.c
@@ -16,8 +16,6 @@
 
 #include "cutils/threads.h"
 
-#if !defined(_WIN32)
-
 // For gettid.
 #if defined(__APPLE__)
 #include "AvailabilityMacros.h"  // For MAC_OS_X_VERSION_MAX_ALLOWED
@@ -30,9 +28,24 @@
 #include <syscall.h>
 #include <unistd.h>
 #elif defined(_WIN32)
-#include <Windows.h>
+#include <windows.h>
 #endif
 
+// No definition needed for Android because we'll just pick up bionic's copy.
+#ifndef __ANDROID__
+pid_t gettid() {
+#if defined(__APPLE__)
+  return syscall(SYS_thread_selfid);
+#elif defined(__linux__)
+  return syscall(__NR_gettid);
+#elif defined(_WIN32)
+  return GetCurrentThreadId();
+#endif
+}
+#endif  // __ANDROID__
+
+#if !defined(_WIN32)
+
 void*  thread_store_get( thread_store_t*  store )
 {
     if (!store->has_tls)
@@ -58,24 +71,6 @@
     pthread_setspecific( store->tls, value );
 }
 
-// No definition needed for Android because we'll just pick up bionic's copy.
-#ifndef __ANDROID__
-pid_t gettid() {
-#if defined(__APPLE__)
-  uint64_t owner;
-  int rc = pthread_threadid_np(NULL, &owner);
-  if (rc != 0) {
-    abort();
-  }
-  return owner;
-#elif defined(__linux__)
-  return syscall(__NR_gettid);
-#elif defined(_WIN32)
-  return (pid_t)GetCurrentThreadId();
-#endif
-}
-#endif  // __ANDROID__
-
 #else /* !defined(_WIN32) */
 void*  thread_store_get( thread_store_t*  store )
 {
diff --git a/liblog/log_read.c b/liblog/log_read.c
index 5364e4f..9c4af30 100644
--- a/liblog/log_read.c
+++ b/liblog/log_read.c
@@ -208,6 +208,7 @@
     [LOG_ID_EVENTS] = "events",
     [LOG_ID_SYSTEM] = "system",
     [LOG_ID_CRASH] = "crash",
+    [LOG_ID_KERNEL] = "kernel",
 };
 
 const char *android_log_id_to_name(log_id_t log_id)
diff --git a/liblog/log_read_kern.c b/liblog/log_read_kern.c
index bdc7b18..69b405c 100644
--- a/liblog/log_read_kern.c
+++ b/liblog/log_read_kern.c
@@ -62,7 +62,8 @@
     [LOG_ID_RADIO] = "radio",
     [LOG_ID_EVENTS] = "events",
     [LOG_ID_SYSTEM] = "system",
-    [LOG_ID_CRASH] = "crash"
+    [LOG_ID_CRASH] = "crash",
+    [LOG_ID_KERNEL] = "kernel",
 };
 
 const char *android_log_id_to_name(log_id_t log_id)
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index c62a246..bdee28f 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -310,7 +310,8 @@
     [LOG_ID_RADIO] = "radio",
     [LOG_ID_EVENTS] = "events",
     [LOG_ID_SYSTEM] = "system",
-    [LOG_ID_CRASH] = "crash"
+    [LOG_ID_CRASH] = "crash",
+    [LOG_ID_KERNEL] = "kernel",
 };
 
 const char *android_log_id_to_name(log_id_t log_id)
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 0f01542..a3f1d7e 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -43,6 +43,7 @@
     FilterInfo *filters;
     AndroidLogPrintFormat format;
     bool colored_output;
+    bool usec_time_output;
 };
 
 /*
@@ -185,6 +186,7 @@
     p_ret->global_pri = ANDROID_LOG_VERBOSE;
     p_ret->format = FORMAT_BRIEF;
     p_ret->colored_output = false;
+    p_ret->usec_time_output = false;
 
     return p_ret;
 }
@@ -207,13 +209,19 @@
 
 
 
-void android_log_setPrintFormat(AndroidLogFormat *p_format,
+int android_log_setPrintFormat(AndroidLogFormat *p_format,
         AndroidLogPrintFormat format)
 {
-    if (format == FORMAT_COLOR)
+    if (format == FORMAT_MODIFIER_COLOR) {
         p_format->colored_output = true;
-    else
-        p_format->format = format;
+        return 0;
+    }
+    if (format == FORMAT_MODIFIER_TIME_USEC) {
+        p_format->usec_time_output = true;
+        return 0;
+    }
+    p_format->format = format;
+    return 1;
 }
 
 /**
@@ -231,7 +239,8 @@
     else if (strcmp(formatString, "time") == 0) format = FORMAT_TIME;
     else if (strcmp(formatString, "threadtime") == 0) format = FORMAT_THREADTIME;
     else if (strcmp(formatString, "long") == 0) format = FORMAT_LONG;
-    else if (strcmp(formatString, "color") == 0) format = FORMAT_COLOR;
+    else if (strcmp(formatString, "color") == 0) format = FORMAT_MODIFIER_COLOR;
+    else if (strcmp(formatString, "usec") == 0) format = FORMAT_MODIFIER_TIME_USEC;
     else format = FORMAT_OFF;
 
     return format;
@@ -745,7 +754,7 @@
     struct tm tmBuf;
 #endif
     struct tm* ptm;
-    char timeBuf[32];
+    char timeBuf[32]; /* good margin, 23+nul for msec, 26+nul for usec */
     char prefixBuf[128], suffixBuf[128];
     char priChar;
     int prefixSuffixIsHeaderFooter = 0;
@@ -771,6 +780,14 @@
 #endif
     //strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
     strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
+    len = strlen(timeBuf);
+    if (p_format->usec_time_output) {
+        snprintf(timeBuf + len, sizeof(timeBuf) - len,
+                 ".%06ld", entry->tv_nsec / 1000);
+    } else {
+        snprintf(timeBuf + len, sizeof(timeBuf) - len,
+                 ".%03ld", entry->tv_nsec / 1000000);
+    }
 
     /*
      * Construct a buffer containing the log header and log message.
@@ -811,23 +828,21 @@
             break;
         case FORMAT_TIME:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "%s.%03ld %c/%-8s(%5d): ", timeBuf, entry->tv_nsec / 1000000,
-                priChar, entry->tag, entry->pid);
+                "%s %c/%-8s(%5d): ", timeBuf, priChar, entry->tag, entry->pid);
             strcpy(suffixBuf + suffixLen, "\n");
             ++suffixLen;
             break;
         case FORMAT_THREADTIME:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "%s.%03ld %5d %5d %c %-8s: ", timeBuf, entry->tv_nsec / 1000000,
+                "%s %5d %5d %c %-8s: ", timeBuf,
                 entry->pid, entry->tid, priChar, entry->tag);
             strcpy(suffixBuf + suffixLen, "\n");
             ++suffixLen;
             break;
         case FORMAT_LONG:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "[ %s.%03ld %5d:%5d %c/%-8s ]\n",
-                timeBuf, entry->tv_nsec / 1000000, entry->pid,
-                entry->tid, priChar, entry->tag);
+                "[ %s %5d:%5d %c/%-8s ]\n",
+                timeBuf, entry->pid, entry->tid, priChar, entry->tag);
             strcpy(suffixBuf + suffixLen, "\n\n");
             suffixLen += 2;
             prefixSuffixIsHeaderFooter = 1;
diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp
index 29501be..0e84f4e 100644
--- a/liblog/tests/libc_test.cpp
+++ b/liblog/tests/libc_test.cpp
@@ -136,3 +136,12 @@
 
     android_logger_list_close(logger_list);
 }
+
+TEST(libc, __pstore_append) {
+    FILE *fp;
+    ASSERT_TRUE(NULL != (fp = fopen("/dev/pmsg0", "a")));
+    static const char message[] = "libc.__pstore_append\n";
+    ASSERT_EQ((size_t)1, fwrite(message, sizeof(message), 1, fp));
+    ASSERT_EQ(0, fclose(fp));
+    fprintf(stderr, "Reboot, ensure string libc.__pstore_append is in /sys/fs/pstore/pmsg-ramoops-0\n");
+}
diff --git a/libmincrypt/Android.mk b/libmincrypt/Android.mk
index 503bcb4..7906986 100644
--- a/libmincrypt/Android.mk
+++ b/libmincrypt/Android.mk
@@ -6,8 +6,6 @@
 LOCAL_MODULE := libmincrypt
 LOCAL_SRC_FILES := dsa_sig.c p256.c p256_ec.c p256_ecdsa.c rsa.c sha.c sha256.c
 LOCAL_CFLAGS := -Wall -Werror
-# Clang's slp-vectorize phase has segmentation fault when compiling p256_ec.c.
-LOCAL_CLANG_CFLAGS += -fno-slp-vectorize
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
diff --git a/libsuspend/autosuspend_autosleep.c b/libsuspend/autosuspend_autosleep.c
index 0d31e74..7262cc7 100644
--- a/libsuspend/autosuspend_autosleep.c
+++ b/libsuspend/autosuspend_autosleep.c
@@ -40,7 +40,7 @@
 
     ALOGV("autosuspend_autosleep_enable\n");
 
-    ret = write(autosleep_fd, sleep_state, strlen(sleep_state));
+    ret = TEMP_FAILURE_RETRY(write(autosleep_fd, sleep_state, strlen(sleep_state)));
     if (ret < 0) {
         strerror_r(errno, buf, sizeof(buf));
         ALOGE("Error writing to %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
@@ -62,7 +62,7 @@
 
     ALOGV("autosuspend_autosleep_disable\n");
 
-    ret = write(autosleep_fd, on_state, strlen(on_state));
+    ret = TEMP_FAILURE_RETRY(write(autosleep_fd, on_state, strlen(on_state)));
     if (ret < 0) {
         strerror_r(errno, buf, sizeof(buf));
         ALOGE("Error writing to %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
@@ -86,7 +86,7 @@
 {
     char buf[80];
 
-    autosleep_fd = open(SYS_POWER_AUTOSLEEP, O_WRONLY);
+    autosleep_fd = TEMP_FAILURE_RETRY(open(SYS_POWER_AUTOSLEEP, O_WRONLY));
     if (autosleep_fd < 0) {
         strerror_r(errno, buf, sizeof(buf));
         ALOGE("Error opening %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
diff --git a/libsuspend/autosuspend_earlysuspend.c b/libsuspend/autosuspend_earlysuspend.c
index 2bece4c..3793a69 100644
--- a/libsuspend/autosuspend_earlysuspend.c
+++ b/libsuspend/autosuspend_earlysuspend.c
@@ -49,11 +49,9 @@
 {
     int err = 0;
     char buf;
-    int fd = open(EARLYSUSPEND_WAIT_FOR_FB_WAKE, O_RDONLY, 0);
+    int fd = TEMP_FAILURE_RETRY(open(EARLYSUSPEND_WAIT_FOR_FB_WAKE, O_RDONLY, 0));
     // if the file doesn't exist, the error will be caught in read() below
-    do {
-        err = read(fd, &buf, 1);
-    } while (err < 0 && errno == EINTR);
+    err = TEMP_FAILURE_RETRY(read(fd, &buf, 1));
     ALOGE_IF(err < 0,
             "*** ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
     close(fd);
@@ -64,11 +62,9 @@
 {
     int err = 0;
     char buf;
-    int fd = open(EARLYSUSPEND_WAIT_FOR_FB_SLEEP, O_RDONLY, 0);
+    int fd = TEMP_FAILURE_RETRY(open(EARLYSUSPEND_WAIT_FOR_FB_SLEEP, O_RDONLY, 0));
     // if the file doesn't exist, the error will be caught in read() below
-    do {
-        err = read(fd, &buf, 1);
-    } while (err < 0 && errno == EINTR);
+    err = TEMP_FAILURE_RETRY(read(fd, &buf, 1));
     ALOGE_IF(err < 0,
             "*** ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
     close(fd);
@@ -134,7 +130,7 @@
 
     ALOGV("autosuspend_earlysuspend_disable\n");
 
-    ret = write(sPowerStatefd, pwr_state_on, strlen(pwr_state_on));
+    ret = TEMP_FAILURE_RETRY(write(sPowerStatefd, pwr_state_on, strlen(pwr_state_on)));
     if (ret < 0) {
         strerror_r(errno, buf, sizeof(buf));
         ALOGE("Error writing to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
@@ -195,7 +191,7 @@
     char buf[80];
     int ret;
 
-    sPowerStatefd = open(EARLYSUSPEND_SYS_POWER_STATE, O_RDWR);
+    sPowerStatefd = TEMP_FAILURE_RETRY(open(EARLYSUSPEND_SYS_POWER_STATE, O_RDWR));
 
     if (sPowerStatefd < 0) {
         strerror_r(errno, buf, sizeof(buf));
@@ -203,7 +199,7 @@
         return NULL;
     }
 
-    ret = write(sPowerStatefd, "on", 2);
+    ret = TEMP_FAILURE_RETRY(write(sPowerStatefd, "on", 2));
     if (ret < 0) {
         strerror_r(errno, buf, sizeof(buf));
         ALOGW("Error writing 'on' to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
diff --git a/libsuspend/autosuspend_wakeup_count.c b/libsuspend/autosuspend_wakeup_count.c
index 7483a8f..ee4ebe7 100644
--- a/libsuspend/autosuspend_wakeup_count.c
+++ b/libsuspend/autosuspend_wakeup_count.c
@@ -51,7 +51,8 @@
         usleep(100000);
         ALOGV("%s: read wakeup_count\n", __func__);
         lseek(wakeup_count_fd, 0, SEEK_SET);
-        wakeup_count_len = read(wakeup_count_fd, wakeup_count, sizeof(wakeup_count));
+        wakeup_count_len = TEMP_FAILURE_RETRY(read(wakeup_count_fd, wakeup_count,
+                sizeof(wakeup_count)));
         if (wakeup_count_len < 0) {
             strerror_r(errno, buf, sizeof(buf));
             ALOGE("Error reading from %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf);
@@ -72,13 +73,13 @@
         }
 
         ALOGV("%s: write %*s to wakeup_count\n", __func__, wakeup_count_len, wakeup_count);
-        ret = write(wakeup_count_fd, wakeup_count, wakeup_count_len);
+        ret = TEMP_FAILURE_RETRY(write(wakeup_count_fd, wakeup_count, wakeup_count_len));
         if (ret < 0) {
             strerror_r(errno, buf, sizeof(buf));
             ALOGE("Error writing to %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf);
         } else {
             ALOGV("%s: write %s to %s\n", __func__, sleep_state, SYS_POWER_STATE);
-            ret = write(state_fd, sleep_state, strlen(sleep_state));
+            ret = TEMP_FAILURE_RETRY(write(state_fd, sleep_state, strlen(sleep_state)));
             if (ret < 0) {
                 strerror_r(errno, buf, sizeof(buf));
                 ALOGE("Error writing to %s: %s\n", SYS_POWER_STATE, buf);
@@ -157,14 +158,14 @@
     int ret;
     char buf[80];
 
-    state_fd = open(SYS_POWER_STATE, O_RDWR);
+    state_fd = TEMP_FAILURE_RETRY(open(SYS_POWER_STATE, O_RDWR));
     if (state_fd < 0) {
         strerror_r(errno, buf, sizeof(buf));
         ALOGE("Error opening %s: %s\n", SYS_POWER_STATE, buf);
         goto err_open_state;
     }
 
-    wakeup_count_fd = open(SYS_POWER_WAKEUP_COUNT, O_RDWR);
+    wakeup_count_fd = TEMP_FAILURE_RETRY(open(SYS_POWER_WAKEUP_COUNT, O_RDWR));
     if (wakeup_count_fd < 0) {
         strerror_r(errno, buf, sizeof(buf));
         ALOGE("Error opening %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf);
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 2b19b93..2c2d785 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -235,7 +235,7 @@
                     "  -r <kbytes>     Rotate log every kbytes. Requires -f\n"
                     "  -n <count>      Sets max number of rotated logs to <count>, default 4\n"
                     "  -v <format>     Sets the log print format, where <format> is:\n\n"
-                    "                  brief color long process raw tag thread threadtime time\n\n"
+                    "                  brief color long process raw tag thread threadtime time usec\n\n"
                     "  -D              print dividers between each log buffer\n"
                     "  -c              clear (flush) the entire log and exit\n"
                     "  -d              dump the log and then exit (don't block)\n"
@@ -291,9 +291,7 @@
         return -1;
     }
 
-    android_log_setPrintFormat(g_logformat, format);
-
-    return 0;
+    return android_log_setPrintFormat(g_logformat, format);
 }
 
 static const char multipliers[][2] = {
@@ -569,10 +567,7 @@
                 if (err < 0) {
                     logcat_panic(true, "Invalid parameter %s to -v\n", optarg);
                 }
-
-                if (strcmp("color", optarg)) { // exception for modifiers
-                    hasSetLogFormat = 1;
-                }
+                hasSetLogFormat |= err;
             break;
 
             case 'Q':
diff --git a/logd/Android.mk b/logd/Android.mk
index e65e9ff..73da8dc 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -18,6 +18,7 @@
     LogWhiteBlackList.cpp \
     libaudit.c \
     LogAudit.cpp \
+    LogKlog.cpp \
     event.logtags
 
 LOCAL_SHARED_LIBRARIES := \
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index bdfed3b..5489cc9 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -33,9 +33,9 @@
 #include "LogCommand.h"
 
 CommandListener::CommandListener(LogBuffer *buf, LogReader * /*reader*/,
-                                 LogListener * /*swl*/)
-        : FrameworkListener(getLogSocket())
-        , mBuf(*buf) {
+                                 LogListener * /*swl*/) :
+        FrameworkListener(getLogSocket()),
+        mBuf(*buf) {
     // registerCmd(new ShutdownCmd(buf, writer, swl));
     registerCmd(new ClearCmd(buf));
     registerCmd(new GetBufSizeCmd(buf));
@@ -48,12 +48,12 @@
 }
 
 CommandListener::ShutdownCmd::ShutdownCmd(LogBuffer *buf, LogReader *reader,
-                                          LogListener *swl)
-        : LogCommand("shutdown")
-        , mBuf(*buf)
-        , mReader(*reader)
-        , mSwl(*swl)
-{ }
+                                          LogListener *swl) :
+        LogCommand("shutdown"),
+        mBuf(*buf),
+        mReader(*reader),
+        mSwl(*swl) {
+}
 
 int CommandListener::ShutdownCmd::runCommand(SocketClient * /*cli*/,
                                              int /*argc*/,
@@ -63,10 +63,10 @@
     exit(0);
 }
 
-CommandListener::ClearCmd::ClearCmd(LogBuffer *buf)
-        : LogCommand("clear")
-        , mBuf(*buf)
-{ }
+CommandListener::ClearCmd::ClearCmd(LogBuffer *buf) :
+        LogCommand("clear"),
+        mBuf(*buf) {
+}
 
 static void setname() {
     static bool name_set;
@@ -100,10 +100,10 @@
     return 0;
 }
 
-CommandListener::GetBufSizeCmd::GetBufSizeCmd(LogBuffer *buf)
-        : LogCommand("getLogSize")
-        , mBuf(*buf)
-{ }
+CommandListener::GetBufSizeCmd::GetBufSizeCmd(LogBuffer *buf) :
+        LogCommand("getLogSize"),
+        mBuf(*buf) {
+}
 
 int CommandListener::GetBufSizeCmd::runCommand(SocketClient *cli,
                                          int argc, char **argv) {
@@ -126,10 +126,10 @@
     return 0;
 }
 
-CommandListener::SetBufSizeCmd::SetBufSizeCmd(LogBuffer *buf)
-        : LogCommand("setLogSize")
-        , mBuf(*buf)
-{ }
+CommandListener::SetBufSizeCmd::SetBufSizeCmd(LogBuffer *buf) :
+        LogCommand("setLogSize"),
+        mBuf(*buf) {
+}
 
 int CommandListener::SetBufSizeCmd::runCommand(SocketClient *cli,
                                          int argc, char **argv) {
@@ -160,10 +160,10 @@
     return 0;
 }
 
-CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer *buf)
-        : LogCommand("getLogSizeUsed")
-        , mBuf(*buf)
-{ }
+CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer *buf) :
+        LogCommand("getLogSizeUsed"),
+        mBuf(*buf) {
+}
 
 int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient *cli,
                                          int argc, char **argv) {
@@ -186,10 +186,10 @@
     return 0;
 }
 
-CommandListener::GetStatisticsCmd::GetStatisticsCmd(LogBuffer *buf)
-        : LogCommand("getStatistics")
-        , mBuf(*buf)
-{ }
+CommandListener::GetStatisticsCmd::GetStatisticsCmd(LogBuffer *buf) :
+        LogCommand("getStatistics"),
+        mBuf(*buf) {
+}
 
 static void package_string(char **strp) {
     const char *a = *strp;
@@ -243,10 +243,10 @@
     return 0;
 }
 
-CommandListener::GetPruneListCmd::GetPruneListCmd(LogBuffer *buf)
-        : LogCommand("getPruneList")
-        , mBuf(*buf)
-{ }
+CommandListener::GetPruneListCmd::GetPruneListCmd(LogBuffer *buf) :
+        LogCommand("getPruneList"),
+        mBuf(*buf) {
+}
 
 int CommandListener::GetPruneListCmd::runCommand(SocketClient *cli,
                                          int /*argc*/, char ** /*argv*/) {
@@ -263,10 +263,10 @@
     return 0;
 }
 
-CommandListener::SetPruneListCmd::SetPruneListCmd(LogBuffer *buf)
-        : LogCommand("setPruneList")
-        , mBuf(*buf)
-{ }
+CommandListener::SetPruneListCmd::SetPruneListCmd(LogBuffer *buf) :
+        LogCommand("setPruneList"),
+        mBuf(*buf) {
+}
 
 int CommandListener::SetPruneListCmd::runCommand(SocketClient *cli,
                                          int argc, char **argv) {
@@ -301,9 +301,8 @@
     return 0;
 }
 
-CommandListener::ReinitCmd::ReinitCmd()
-        : LogCommand("reinit")
-{ }
+CommandListener::ReinitCmd::ReinitCmd() : LogCommand("reinit") {
+}
 
 int CommandListener::ReinitCmd::runCommand(SocketClient *cli,
                                          int /*argc*/, char ** /*argv*/) {
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
index 26a1861..d584925 100644
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -27,14 +27,14 @@
                            unsigned long tail,
                            unsigned int logMask,
                            pid_t pid,
-                           uint64_t start)
-        : mReader(reader)
-        , mNonBlock(nonBlock)
-        , mTail(tail)
-        , mLogMask(logMask)
-        , mPid(pid)
-        , mStart(start)
-{ }
+                           uint64_t start) :
+        mReader(reader),
+        mNonBlock(nonBlock),
+        mTail(tail),
+        mLogMask(logMask),
+        mPid(pid),
+        mStart(start) {
+}
 
 // runSocketCommand is called once for every open client on the
 // log reader socket. Here we manage and associated the reader
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index caae54b..4ec2e59 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -29,6 +29,7 @@
 
 #include "libaudit.h"
 #include "LogAudit.h"
+#include "LogKlog.h"
 
 #define KMSG_PRIORITY(PRI)                          \
     '<',                                            \
@@ -36,12 +37,12 @@
     '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) % 10, \
     '>'
 
-LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg)
-        : SocketListener(getLogSocket(), false)
-        , logbuf(buf)
-        , reader(reader)
-        , fdDmesg(fdDmesg)
-        , initialized(false) {
+LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg) :
+        SocketListener(getLogSocket(), false),
+        logbuf(buf),
+        reader(reader),
+        fdDmesg(fdDmesg),
+        initialized(false) {
     static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO),
         'l', 'o', 'g', 'd', '.', 'a', 'u', 'd', 'i', 't', 'd', ':',
         ' ', 's', 't', 'a', 'r', 't', '\n' };
@@ -121,6 +122,15 @@
             && (*cp == ':')) {
         memcpy(timeptr + sizeof(audit_str) - 1, "0.0", 3);
         memmove(timeptr + sizeof(audit_str) - 1 + 3, cp, strlen(cp) + 1);
+        //
+        // We are either in 1970ish (MONOTONIC) or 2015+ish (REALTIME) so to
+        // differentiate without prejudice, we use 1980 to delineate, earlier
+        // is monotonic, later is real.
+        //
+#       define EPOCH_PLUS_10_YEARS (10 * 1461 / 4 * 24 * 60 * 60)
+        if (now.tv_sec < EPOCH_PLUS_10_YEARS) {
+            LogKlog::convertMonotonicToReal(now);
+        }
     } else {
         now.strptime("", ""); // side effect of setting CLOCK_REALTIME
     }
@@ -223,7 +233,7 @@
 int LogAudit::log(char *buf) {
     char *audit = strstr(buf, " audit(");
     if (!audit) {
-        return -EXDEV;
+        return 0;
     }
 
     *audit = '\0';
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index b6b6124..8c0a0be 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -126,8 +126,7 @@
     }
 }
 
-LogBuffer::LogBuffer(LastLogTimes *times)
-        : mTimes(*times) {
+LogBuffer::LogBuffer(LastLogTimes *times) : mTimes(*times) {
     pthread_mutex_init(&mLogElementsLock, NULL);
 
     init();
@@ -296,7 +295,8 @@
         ssize_t index = -1;
         while((index = next(index)) >= 0) {
             LogBufferElement *l = editEntryAt(index).getLast();
-            if ((l->getDropped() >= 4) && (current > l->getRealTime().nsec())) {
+            if ((l->getDropped() >= EXPIRE_THRESHOLD)
+                    && (current > l->getRealTime().nsec())) {
                 removeAt(index);
                 index = -1;
             }
@@ -388,6 +388,7 @@
         bool kick = false;
         bool leading = true;
         LogBufferElementLast last;
+        log_time start(log_time::EPOCH);
         for(it = mLogElements.begin(); it != mLogElements.end();) {
             LogBufferElement *e = *it;
 
@@ -447,11 +448,29 @@
             }
 
             if (e->getUid() != worst) {
+                if (start != log_time::EPOCH) {
+                    static const timespec too_old = {
+                        EXPIRE_HOUR_THRESHOLD * 60 * 60, 0
+                    };
+                    start = e->getRealTime() + too_old;
+                }
                 last.clear(e);
                 ++it;
                 continue;
             }
 
+            if ((start != log_time::EPOCH) && (e->getRealTime() > start)) {
+                // KISS. Really a heuristic rather than algorithmically strong,
+                // a crude mechanism, the following loops will move the oldest
+                // watermark possibly wiping out the extra EXPIRE_HOUR_THRESHOLD
+                // we just thought we were preserving. We count on the typical
+                // pruneRows of 10% of total not being a sledgehammer.
+                // A stronger algorithm would have us loop back to the top if
+                // we have worst-UID enabled and we start expiring messages
+                // below less than EXPIRE_HOUR_THRESHOLD old.
+                break;
+            }
+
             pruneRows--;
             if (pruneRows == 0) {
                 break;
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 6a05700..3d7237e 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -34,14 +34,14 @@
 
 LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime,
                                    uid_t uid, pid_t pid, pid_t tid,
-                                   const char *msg, unsigned short len)
-        : mLogId(log_id)
-        , mUid(uid)
-        , mPid(pid)
-        , mTid(tid)
-        , mMsgLen(len)
-        , mSequence(sequence.fetch_add(1, memory_order_relaxed))
-        , mRealTime(realtime) {
+                                   const char *msg, unsigned short len) :
+        mLogId(log_id),
+        mUid(uid),
+        mPid(pid),
+        mTid(tid),
+        mMsgLen(len),
+        mSequence(sequence.fetch_add(1, memory_order_relaxed)),
+        mRealTime(realtime) {
     mMsg = new char[len];
     memcpy(mMsg, msg, len);
 }
@@ -50,8 +50,15 @@
     delete [] mMsg;
 }
 
+uint32_t LogBufferElement::getTag() const {
+    if ((mLogId != LOG_ID_EVENTS) || !mMsg || (mMsgLen < sizeof(uint32_t))) {
+        return 0;
+    }
+    return le32toh(reinterpret_cast<android_event_header_t *>(mMsg)->tag);
+}
+
 // caller must own and free character string
-static char *tidToName(pid_t tid) {
+char *android::tidToName(pid_t tid) {
     char *retval = NULL;
     char buffer[256];
     snprintf(buffer, sizeof(buffer), "/proc/%u/comm", tid);
@@ -101,9 +108,9 @@
     static const char format_uid[] = "uid=%u%s too chatty%s, expire %u line%s";
 
     char *name = parent->uidToName(mUid);
-    char *commName = tidToName(mTid);
+    char *commName = android::tidToName(mTid);
     if (!commName && (mTid != mPid)) {
-        commName = tidToName(mPid);
+        commName = android::tidToName(mPid);
     }
     if (!commName) {
         commName = parent->pidToName(mPid);
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index b6c6196..3dcf9d1 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -35,15 +35,24 @@
 
 // Furnished in LogStatistics.cpp. Caller must own and free returned value
 char *pidToName(pid_t pid);
+char *tidToName(pid_t tid);
+
+// Furnished in main.cpp. Thread safe.
+const char *tagToName(uint32_t tag);
 
 }
 
 static inline bool worstUidEnabledForLogid(log_id_t id) {
-    return (id != LOG_ID_CRASH) && (id != LOG_ID_EVENTS);
+    return (id != LOG_ID_CRASH) && (id != LOG_ID_KERNEL) && (id != LOG_ID_EVENTS);
 }
 
 class LogBuffer;
 
+#define EXPIRE_HOUR_THRESHOLD 24 // Only expire chatty UID logs to preserve
+                                 // non-chatty UIDs less than this age in hours
+#define EXPIRE_THRESHOLD 4       // A smaller expire count is considered too
+                                 // chatty for the temporal expire messages
+
 class LogBufferElement {
     const log_id_t mLogId;
     const uid_t mUid;
@@ -85,6 +94,8 @@
     static uint64_t getCurrentSequence(void) { return sequence.load(memory_order_relaxed); }
     log_time getRealTime(void) const { return mRealTime; }
 
+    uint32_t getTag(void) const;
+
     static const uint64_t FLUSH_ERROR;
     uint64_t flushTo(SocketClient *writer, LogBuffer *parent);
 };
diff --git a/logd/LogCommand.cpp b/logd/LogCommand.cpp
index b78c0e0..06d865c 100644
--- a/logd/LogCommand.cpp
+++ b/logd/LogCommand.cpp
@@ -23,8 +23,7 @@
 
 #include "LogCommand.h"
 
-LogCommand::LogCommand(const char *cmd)
-        : FrameworkCommand(cmd) {
+LogCommand::LogCommand(const char *cmd) : FrameworkCommand(cmd) {
 }
 
 // gets a list of supplementary group IDs associated with
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
new file mode 100644
index 0000000..8df0d0a
--- /dev/null
+++ b/logd/LogKlog.cpp
@@ -0,0 +1,454 @@
+/*
+ * 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 <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/prctl.h>
+#include <sys/uio.h>
+#include <syslog.h>
+
+#include <log/logger.h>
+
+#include "LogKlog.h"
+
+#define KMSG_PRIORITY(PRI)           \
+    '<',                             \
+    '0' + (LOG_SYSLOG | (PRI)) / 10, \
+    '0' + (LOG_SYSLOG | (PRI)) % 10, \
+    '>'
+
+static const char priority_message[] = { KMSG_PRIORITY(LOG_INFO), '\0' };
+
+log_time LogKlog::correction = log_time(CLOCK_REALTIME) - log_time(CLOCK_MONOTONIC);
+
+LogKlog::LogKlog(LogBuffer *buf, LogReader *reader, int fdWrite, int fdRead, bool auditd) :
+        SocketListener(fdRead, false),
+        logbuf(buf),
+        reader(reader),
+        signature(CLOCK_MONOTONIC),
+        fdWrite(fdWrite),
+        fdRead(fdRead),
+        initialized(false),
+        enableLogging(true),
+        auditd(auditd) {
+    static const char klogd_message[] = "%slogd.klogd: %" PRIu64 "\n";
+    char buffer[sizeof(priority_message) + sizeof(klogd_message) + 20 - 4];
+    snprintf(buffer, sizeof(buffer), klogd_message, priority_message,
+        signature.nsec());
+    write(fdWrite, buffer, strlen(buffer));
+}
+
+bool LogKlog::onDataAvailable(SocketClient *cli) {
+    if (!initialized) {
+        prctl(PR_SET_NAME, "logd.klogd");
+        initialized = true;
+        enableLogging = false;
+    }
+
+    char buffer[LOGGER_ENTRY_MAX_PAYLOAD];
+    size_t len = 0;
+
+    for(;;) {
+        ssize_t retval = 0;
+        if ((sizeof(buffer) - 1 - len) > 0) {
+            retval = read(cli->getSocket(), buffer + len, sizeof(buffer) - 1 - len);
+        }
+        if ((retval == 0) && (len == 0)) {
+            break;
+        }
+        if (retval < 0) {
+            return false;
+        }
+        len += retval;
+        bool full = len == (sizeof(buffer) - 1);
+        char *ep = buffer + len;
+        *ep = '\0';
+        len = 0;
+        for(char *ptr, *tok = buffer;
+                ((tok = strtok_r(tok, "\r\n", &ptr)));
+                tok = NULL) {
+            if (((tok + strlen(tok)) == ep) && (retval != 0) && full) {
+                len = strlen(tok);
+                memmove(buffer, tok, len);
+                break;
+            }
+            if (*tok) {
+                log(tok);
+            }
+        }
+    }
+
+    return true;
+}
+
+
+void LogKlog::calculateCorrection(const log_time &monotonic,
+                                  const char *real_string) {
+    log_time real;
+    if (!real.strptime(real_string, "%Y-%m-%d %H:%M:%S.%09q UTC")) {
+        return;
+    }
+    // kernel report UTC, log_time::strptime is localtime from calendar.
+    // Bionic and liblog strptime does not support %z or %Z to pick up
+    // timezone so we are calculating our own correction.
+    time_t now = real.tv_sec;
+    struct tm tm;
+    memset(&tm, 0, sizeof(tm));
+    tm.tm_isdst = -1;
+    localtime_r(&now, &tm);
+    real.tv_sec += tm.tm_gmtoff;
+    correction = real - monotonic;
+}
+
+void LogKlog::sniffTime(log_time &now, const char **buf, bool reverse) {
+    const char *cp;
+    if ((cp = now.strptime(*buf, "[ %s.%q]"))) {
+        static const char suspend[] = "PM: suspend entry ";
+        static const char resume[] = "PM: suspend exit ";
+        static const char suspended[] = "Suspended for ";
+
+        if (isspace(*cp)) {
+            ++cp;
+        }
+        if (!strncmp(cp, suspend, sizeof(suspend) - 1)) {
+            calculateCorrection(now, cp + sizeof(suspend) - 1);
+        } else if (!strncmp(cp, resume, sizeof(resume) - 1)) {
+            calculateCorrection(now, cp + sizeof(resume) - 1);
+        } else if (!strncmp(cp, suspended, sizeof(suspended) - 1)) {
+            log_time real;
+            char *endp;
+            real.tv_sec = strtol(cp + sizeof(suspended) - 1, &endp, 10);
+            if (*endp == '.') {
+                real.tv_nsec = strtol(endp + 1, &endp, 10) * 1000000L;
+                if (reverse) {
+                    correction -= real;
+                } else {
+                    correction += real;
+                }
+            }
+        }
+
+        convertMonotonicToReal(now);
+        *buf = cp;
+    } else {
+        now = log_time(CLOCK_REALTIME);
+    }
+}
+
+// Passed the entire SYSLOG_ACTION_READ_ALL buffer and interpret a
+// compensated start time.
+void LogKlog::synchronize(const char *buf) {
+    const char *cp = strstr(buf, "] PM: suspend e");
+    if (!cp) {
+        return;
+    }
+
+    do {
+        --cp;
+    } while ((cp > buf) && (isdigit(*cp) || isspace(*cp) || (*cp == '.')));
+
+    log_time now;
+    sniffTime(now, &cp, true);
+
+    char *suspended = strstr(buf, "] Suspended for ");
+    if (!suspended || (suspended > cp)) {
+        return;
+    }
+    cp = suspended;
+
+    do {
+        --cp;
+    } while ((cp > buf) && (isdigit(*cp) || isspace(*cp) || (*cp == '.')));
+
+    sniffTime(now, &cp, true);
+}
+
+// kernel log prefix, convert to a kernel log priority number
+static int parseKernelPrio(const char **buf) {
+    int pri = LOG_USER | LOG_INFO;
+    const char *cp = *buf;
+    if (*cp == '<') {
+        pri = 0;
+        while(isdigit(*++cp)) {
+            pri = (pri * 10) + *cp - '0';
+        }
+        if (*cp == '>') {
+            ++cp;
+        } else {
+            cp = *buf;
+            pri = LOG_USER | LOG_INFO;
+        }
+        *buf = cp;
+    }
+    return pri;
+}
+
+// Convert kernel log priority number into an Android Logger priority number
+static int convertKernelPrioToAndroidPrio(int pri) {
+    switch(pri & LOG_PRIMASK) {
+    case LOG_EMERG:
+        // FALLTHRU
+    case LOG_ALERT:
+        // FALLTHRU
+    case LOG_CRIT:
+        return ANDROID_LOG_FATAL;
+
+    case LOG_ERR:
+        return ANDROID_LOG_ERROR;
+
+    case LOG_WARNING:
+        return ANDROID_LOG_WARN;
+
+    default:
+        // FALLTHRU
+    case LOG_NOTICE:
+        // FALLTHRU
+    case LOG_INFO:
+        break;
+
+    case LOG_DEBUG:
+        return ANDROID_LOG_DEBUG;
+    }
+
+    return ANDROID_LOG_INFO;
+}
+
+//
+// log a message into the kernel log buffer
+//
+// Filter rules to parse <PRI> <TIME> <tag> and <message> in order for
+// them to appear correct in the logcat output:
+//
+// LOG_KERN (0):
+// <PRI>[<TIME>] <tag> ":" <message>
+// <PRI>[<TIME>] <tag> <tag> ":" <message>
+// <PRI>[<TIME>] <tag> <tag>_work ":" <message>
+// <PRI>[<TIME>] <tag> '<tag>.<num>' ":" <message>
+// <PRI>[<TIME>] <tag> '<tag><num>' ":" <message>
+// <PRI>[<TIME>] <tag>_host '<tag>.<num>' ":" <message>
+// (unimplemented) <PRI>[<TIME>] <tag> '<num>.<tag>' ":" <message>
+// <PRI>[<TIME>] "[INFO]"<tag> : <message>
+// <PRI>[<TIME>] "------------[ cut here ]------------"   (?)
+// <PRI>[<TIME>] "---[ end trace 3225a3070ca3e4ac ]---"   (?)
+// LOG_USER, LOG_MAIL, LOG_DAEMON, LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS
+// LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_FTP:
+// <PRI+TAG>[<TIME>] (see sys/syslog.h)
+// Observe:
+//  Minimum tag length = 3   NB: drops things like r5:c00bbadf, but allow PM:
+//  Maximum tag words = 2
+//  Maximum tag length = 16  NB: we are thinking of how ugly logcat can get.
+//  Not a Tag if there is no message content.
+//  leading additional spaces means no tag, inherit last tag.
+//  Not a Tag if <tag>: is "ERROR:", "WARNING:", "INFO:" or "CPU:"
+// Drop:
+//  empty messages
+//  messages with ' audit(' in them if auditd is running
+//  logd.klogd:
+// return -1 if message logd.klogd: <signature>
+//
+int LogKlog::log(const char *buf) {
+    if (auditd && strstr(buf, " audit(")) {
+        return 0;
+    }
+
+    int pri = parseKernelPrio(&buf);
+
+    log_time now;
+    sniffTime(now, &buf, false);
+
+    // sniff for start marker
+    const char klogd_message[] = "logd.klogd: ";
+    if (!strncmp(buf, klogd_message, sizeof(klogd_message) - 1)) {
+        char *endp;
+        uint64_t sig = strtoll(buf + sizeof(klogd_message) - 1, &endp, 10);
+        if (sig == signature.nsec()) {
+            if (initialized) {
+                enableLogging = true;
+            } else {
+                enableLogging = false;
+            }
+            return -1;
+        }
+        return 0;
+    }
+
+    if (!enableLogging) {
+        return 0;
+    }
+
+    // Parse pid, tid and uid (not possible)
+    const pid_t pid = 0;
+    const pid_t tid = 0;
+    const uid_t uid = 0;
+
+    // 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
+    // beautify the kernel logs into an Android Logging format; the goal is
+    // admirable but costly.
+    while (isspace(*buf)) {
+        ++buf;
+    }
+    if (!*buf) {
+        return 0;
+    }
+    const char *start = buf;
+    const char *tag = "";
+    const char *etag = tag;
+    if (!isspace(*buf)) {
+        const char *bt, *et, *cp;
+
+        bt = buf;
+        if (!strncmp(buf, "[INFO]", 6)) {
+            // <PRI>[<TIME>] "[INFO]"<tag> ":" message
+            bt = buf + 6;
+        }
+        for(et = bt; *et && (*et != ':') && !isspace(*et); ++et);
+        for(cp = et; isspace(*cp); ++cp);
+        size_t size;
+
+        if (*cp == ':') {
+            // One Word
+            tag = bt;
+            etag = et;
+            buf = cp + 1;
+        } else {
+            size = et - bt;
+            if (strncmp(bt, cp, size)) {
+                // <PRI>[<TIME>] <tag>_host '<tag>.<num>' : message
+                if (!strncmp(bt + size - 5, "_host", 5)
+                 && !strncmp(bt, cp, size - 5)) {
+                    const char *b = cp;
+                    cp += size - 5;
+                    if (*cp == '.') {
+                        while (!isspace(*++cp) && (*cp != ':'));
+                        const char *e;
+                        for(e = cp; isspace(*cp); ++cp);
+                        if (*cp == ':') {
+                            tag = b;
+                            etag = e;
+                            buf = cp + 1;
+                        }
+                    }
+                } else {
+                    while (!isspace(*++cp) && (*cp != ':'));
+                    const char *e;
+                    for(e = cp; isspace(*cp); ++cp);
+                    // Two words
+                    if (*cp == ':') {
+                        tag = bt;
+                        etag = e;
+                        buf = cp + 1;
+                    }
+                }
+            } else if (isspace(cp[size])) {
+                const char *b = cp;
+                cp += size;
+                while (isspace(*++cp));
+                // <PRI>[<TIME>] <tag> <tag> : message
+                if (*cp == ':') {
+                    tag = bt;
+                    etag = et;
+                    buf = cp + 1;
+                }
+            } else if (cp[size] == ':') {
+                // <PRI>[<TIME>] <tag> <tag> : message
+                tag = bt;
+                etag = et;
+                buf = 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;
+                while (!isspace(*++cp) && (*cp != ':'));
+                const char *e = cp;
+                while (isspace(*cp)) {
+                    ++cp;
+                }
+                if (*cp == ':') {
+                    tag = b;
+                    etag = e;
+                    buf = cp + 1;
+                }
+            } else {
+                while (!isspace(*++cp) && (*cp != ':'));
+                const char *e = cp;
+                while (isspace(*cp)) {
+                    ++cp;
+                }
+                // Two words
+                if (*cp == ':') {
+                    tag = bt;
+                    etag = e;
+                    buf = cp + 1;
+                }
+            }
+        }
+        size = etag - tag;
+        if ((size <= 1)
+         || ((size == 2) && (isdigit(tag[0]) || isdigit(tag[1])))
+         || ((size == 3) && !strncmp(tag, "CPU", 3))
+         || ((size == 7) && !strncmp(tag, "WARNING", 7))
+         || ((size == 5) && !strncmp(tag, "ERROR", 5))
+         || ((size == 4) && !strncmp(tag, "INFO", 4))) {
+            buf = start;
+            etag = tag = "";
+        }
+    }
+    size_t l = etag - tag;
+    while (isspace(*buf)) {
+        ++buf;
+    }
+    size_t n = 1 + l + 1 + strlen(buf) + 1;
+
+    // Allocate a buffer to hold the interpreted log message
+    int rc = n;
+    char *newstr = reinterpret_cast<char *>(malloc(n));
+    if (!newstr) {
+        rc = -ENOMEM;
+        return rc;
+    }
+    char *np = newstr;
+
+    // Convert priority into single-byte Android logger priority
+    *np = convertKernelPrioToAndroidPrio(pri);
+    ++np;
+
+    // Copy parsed tag following priority
+    strncpy(np, tag, l);
+    np += l;
+    *np = '\0';
+    ++np;
+
+    // Copy main message to the remainder
+    strcpy(np, buf);
+
+    // Log message
+    rc = logbuf->log(LOG_ID_KERNEL, now, uid, pid, tid, newstr,
+                     (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
+    free(newstr);
+
+    // notify readers
+    if (!rc) {
+        reader->notifyNewLog();
+    }
+
+    return rc;
+}
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
new file mode 100644
index 0000000..8de9c87
--- /dev/null
+++ b/logd/LogKlog.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#ifndef _LOGD_LOG_KLOG_H__
+#define _LOGD_LOG_KLOG_H__
+
+#include <sysutils/SocketListener.h>
+#include <log/log_read.h>
+#include "LogReader.h"
+
+class LogKlog : public SocketListener {
+    LogBuffer *logbuf;
+    LogReader *reader;
+    const log_time signature;
+    const int fdWrite; // /dev/kmsg
+    const int fdRead;  // /proc/kmsg
+    // Set once thread is started, separates KLOG_ACTION_READ_ALL
+    // and KLOG_ACTION_READ phases.
+    bool initialized;
+    // Used during each of the above phases to control logging.
+    bool enableLogging;
+    // set if we are also running auditd, to filter out audit reports from
+    // our copy of the kernel log
+    bool auditd;
+
+    static log_time correction;
+
+public:
+    LogKlog(LogBuffer *buf, LogReader *reader, int fdWrite, int fdRead, bool auditd);
+    int log(const char *buf);
+    void synchronize(const char *buf);
+
+    static void convertMonotonicToReal(log_time &real) { real += correction; }
+
+protected:
+    void sniffTime(log_time &now, const char **buf, bool reverse);
+    void calculateCorrection(const log_time &monotonic, const char *real_string);
+    virtual bool onDataAvailable(SocketClient *cli);
+
+};
+
+#endif
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index 05ced06..b29f5ab 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -28,11 +28,11 @@
 
 #include "LogListener.h"
 
-LogListener::LogListener(LogBuffer *buf, LogReader *reader)
-        : SocketListener(getLogSocket(), false)
-        , logbuf(buf)
-        , reader(reader)
-{  }
+LogListener::LogListener(LogBuffer *buf, LogReader *reader) :
+        SocketListener(getLogSocket(), false),
+        logbuf(buf),
+        reader(reader) {
+}
 
 bool LogListener::onDataAvailable(SocketClient *cli) {
     static bool name_set;
@@ -88,7 +88,7 @@
     }
 
     android_log_header_t *header = reinterpret_cast<android_log_header_t *>(buffer);
-    if (/* header->id < LOG_ID_MIN || */ header->id >= LOG_ID_MAX) {
+    if (/* header->id < LOG_ID_MIN || */ header->id >= LOG_ID_MAX || header->id == LOG_ID_KERNEL) {
         return false;
     }
 
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 745e847..c7deec0 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -24,10 +24,10 @@
 #include "LogReader.h"
 #include "FlushCommand.h"
 
-LogReader::LogReader(LogBuffer *logbuf)
-        : SocketListener(getLogSocket(), true)
-        , mLogbuf(*logbuf)
-{ }
+LogReader::LogReader(LogBuffer *logbuf) :
+        SocketListener(getLogSocket(), true),
+        mLogbuf(*logbuf) {
+}
 
 // When we are notified a new log entry is available, inform
 // all of our listening sockets.
@@ -116,14 +116,14 @@
             uint64_t last;
 
         public:
-            LogFindStart(unsigned logMask, pid_t pid, log_time &start, uint64_t &sequence)
-                    : mPid(pid)
-                    , mLogMask(logMask)
-                    , startTimeSet(false)
-                    , start(start)
-                    , sequence(sequence)
-                    , last(sequence)
-            { }
+            LogFindStart(unsigned logMask, pid_t pid, log_time &start, uint64_t &sequence) :
+                    mPid(pid),
+                    mLogMask(logMask),
+                    startTimeSet(false),
+                    start(start),
+                    sequence(sequence),
+                    last(sequence) {
+            }
 
             static int callback(const LogBufferElement *element, void *obj) {
                 LogFindStart *me = reinterpret_cast<LogFindStart *>(obj);
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 10f7255..90c49c0 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -26,8 +26,7 @@
 
 #include "LogStatistics.h"
 
-LogStatistics::LogStatistics()
-        : enable(false) {
+LogStatistics::LogStatistics() : enable(false) {
     log_id_for_each(id) {
         mSizes[id] = 0;
         mElements[id] = 0;
@@ -41,8 +40,8 @@
 // caller must own and free character string
 char *pidToName(pid_t pid) {
     char *retval = NULL;
-    if (pid == 0) { // special case from auditd for kernel
-        retval = strdup("logd.auditd");
+    if (pid == 0) { // special case from auditd/klogd for kernel
+        retval = strdup("logd");
     } else {
         char buffer[512];
         snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
@@ -70,16 +69,26 @@
     mSizes[log_id] += size;
     ++mElements[log_id];
 
-    uidTable[log_id].add(e->getUid(), e);
-
     mSizesTotal[log_id] += size;
     ++mElementsTotal[log_id];
 
+    if (log_id == LOG_ID_KERNEL) {
+        return;
+    }
+
+    uidTable[log_id].add(e->getUid(), e);
+
     if (!enable) {
         return;
     }
 
     pidTable.add(e->getPid(), e);
+    tidTable.add(e->getTid(), e);
+
+    uint32_t tag = e->getTag();
+    if (tag) {
+        tagTable.add(tag, e);
+    }
 }
 
 void LogStatistics::subtract(LogBufferElement *e) {
@@ -88,6 +97,10 @@
     mSizes[log_id] -= size;
     --mElements[log_id];
 
+    if (log_id == LOG_ID_KERNEL) {
+        return;
+    }
+
     uidTable[log_id].subtract(e->getUid(), e);
 
     if (!enable) {
@@ -95,6 +108,12 @@
     }
 
     pidTable.subtract(e->getPid(), e);
+    tidTable.subtract(e->getTid(), e);
+
+    uint32_t tag = e->getTag();
+    if (tag) {
+        tagTable.subtract(tag, e);
+    }
 }
 
 // Atomically set an entry to drop
@@ -111,6 +130,7 @@
     }
 
     pidTable.drop(e->getPid(), e);
+    tidTable.drop(e->getTid(), e);
 }
 
 // caller must own and free character string
@@ -131,7 +151,11 @@
     }
 
     // Parse /data/system/packages.list
-    char *name = android::uidToName(uid);
+    uid_t userId = uid % AID_USER;
+    char *name = android::uidToName(userId);
+    if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
+        name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
+    }
     if (name) {
         return name;
     }
@@ -149,7 +173,8 @@
                     name = strdup(n);
                 } else if (strcmp(name, n)) {
                     free(name);
-                    return NULL;
+                    name = NULL;
+                    break;
                 }
             }
         }
@@ -368,6 +393,108 @@
         }
     }
 
+    if (enable) {
+        // Tid table
+        bool headerPrinted = false;
+        // sort() returns list of references, unique_ptr makes sure self-delete
+        std::unique_ptr<const TidEntry *[]> sorted = tidTable.sort(maximum_sorted_entries);
+        ssize_t index = -1;
+        while ((index = tidTable.next(index, sorted, maximum_sorted_entries)) >= 0) {
+            const TidEntry *entry = sorted[index];
+            uid_t u = entry->getUid();
+            if ((uid != AID_ROOT) && (u != uid)) {
+                continue;
+            }
+
+            if (!headerPrinted) { // Only print header if we have table to print
+                output.appendFormat("\n\n");
+                android::String8 name("Chattiest TIDs:");
+                android::String8 size("Size");
+                android::String8 pruned("Pruned");
+                format_line(output, name, size, pruned);
+
+                name.setTo("  TID/UID   COMM");
+                size.setTo("BYTES");
+                pruned.setTo("LINES");
+                format_line(output, name, size, pruned);
+
+                headerPrinted = true;
+            }
+
+            android::String8 name("");
+            name.appendFormat("%5u/%u", entry->getKey(), u);
+            const char *n = entry->getName();
+            if (n) {
+                name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", n);
+            } else {
+                // if we do not have a PID name, lets punt to try UID name?
+                char *un = uidToName(u);
+                if (un) {
+                    name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", un);
+                    free(un);
+                }
+                // We tried, better to not have a name at all, we still
+                // have TID/UID by number to report in any case.
+            }
+
+            android::String8 size("");
+            size.appendFormat("%zu", entry->getSizes());
+
+            android::String8 pruned("");
+            size_t dropped = entry->getDropped();
+            if (dropped) {
+                pruned.appendFormat("%zu", dropped);
+            }
+
+            format_line(output, name, size, pruned);
+        }
+    }
+
+    if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
+        // Tag table
+        bool headerPrinted = false;
+        std::unique_ptr<const TagEntry *[]> sorted = tagTable.sort(maximum_sorted_entries);
+        ssize_t index = -1;
+        while ((index = tagTable.next(index, sorted, maximum_sorted_entries)) >= 0) {
+            const TagEntry *entry = sorted[index];
+            uid_t u = entry->getUid();
+            if ((uid != AID_ROOT) && (u != uid)) {
+                continue;
+            }
+
+            android::String8 pruned("");
+
+            if (!headerPrinted) {
+                output.appendFormat("\n\n");
+                android::String8 name("Chattiest events log buffer TAGs:");
+                android::String8 size("Size");
+                format_line(output, name, size, pruned);
+
+                name.setTo("    TAG/UID   TAGNAME");
+                size.setTo("BYTES");
+                format_line(output, name, size, pruned);
+
+                headerPrinted = true;
+            }
+
+            android::String8 name("");
+            if (u == (uid_t)-1) {
+                name.appendFormat("%7u", entry->getKey());
+            } else {
+                name.appendFormat("%7u/%u", entry->getKey(), u);
+            }
+            const char *n = entry->getName();
+            if (n) {
+                name.appendFormat("%*s%s", (int)std::max(14 - name.length(), (size_t)1), "", n);
+            }
+
+            android::String8 size("");
+            size.appendFormat("%zu", entry->getSizes());
+
+            format_line(output, name, size, pruned);
+        }
+    }
+
     *buf = strdup(output.string());
 }
 
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index a935c27..f60f3ed 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -154,8 +154,6 @@
 };
 
 namespace android {
-// caller must own and free character string
-char *pidToName(pid_t pid);
 uid_t pidToUid(pid_t pid);
 }
 
@@ -186,6 +184,10 @@
     const char*getName() const { return name; }
 
     inline void add(pid_t p) {
+        if (name && !strncmp(name, "zygote", 6)) {
+            free(name);
+            name = NULL;
+        }
         if (!name) {
             char *n = android::pidToName(p);
             if (n) {
@@ -205,7 +207,80 @@
         }
         EntryBaseDropped::add(e);
     }
+};
 
+struct TidEntry : public EntryBaseDropped {
+    const pid_t tid;
+    uid_t uid;
+    char *name;
+
+    TidEntry(pid_t t):
+        EntryBaseDropped(),
+        tid(t),
+        uid(android::pidToUid(t)),
+        name(android::tidToName(tid)) { }
+    TidEntry(LogBufferElement *e):
+        EntryBaseDropped(e),
+        tid(e->getTid()),
+        uid(e->getUid()),
+        name(android::tidToName(e->getTid())) { }
+    TidEntry(const TidEntry &c):
+        EntryBaseDropped(c),
+        tid(c.tid),
+        uid(c.uid),
+        name(c.name ? strdup(c.name) : NULL) { }
+    ~TidEntry() { free(name); }
+
+    const pid_t&getKey() const { return tid; }
+    const uid_t&getUid() const { return uid; }
+    const char*getName() const { return name; }
+
+    inline void add(pid_t t) {
+        if (name && !strncmp(name, "zygote", 6)) {
+            free(name);
+            name = NULL;
+        }
+        if (!name) {
+            char *n = android::tidToName(t);
+            if (n) {
+                name = n;
+            }
+        }
+    }
+
+    inline void add(LogBufferElement *e) {
+        uid_t u = e->getUid();
+        if (getUid() != u) {
+            uid = u;
+            free(name);
+            name = android::tidToName(e->getTid());
+        } else {
+            add(e->getTid());
+        }
+        EntryBaseDropped::add(e);
+    }
+};
+
+struct TagEntry : public EntryBase {
+    const uint32_t tag;
+    uid_t uid;
+
+    TagEntry(LogBufferElement *e):
+        EntryBase(e),
+        tag(e->getTag()),
+        uid(e->getUid()) { }
+
+    const uint32_t&getKey() const { return tag; }
+    const uid_t&getUid() const { return uid; }
+    const char*getName() const { return android::tagToName(tag); }
+
+    inline void add(LogBufferElement *e) {
+        uid_t u = e->getUid();
+        if (uid != u) {
+            uid = -1;
+        }
+        EntryBase::add(e);
+    }
 };
 
 // Log Statistics
@@ -224,6 +299,14 @@
     typedef LogHashtable<pid_t, PidEntry> pidTable_t;
     pidTable_t pidTable;
 
+    // tid to uid list
+    typedef LogHashtable<pid_t, TidEntry> tidTable_t;
+    tidTable_t tidTable;
+
+    // tag list
+    typedef LogHashtable<uint32_t, TagEntry> tagTable_t;
+    tagTable_t tagTable;
+
 public:
     LogStatistics();
 
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index 1b60b7e..ec67c07 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -26,24 +26,23 @@
 LogTimeEntry::LogTimeEntry(LogReader &reader, SocketClient *client,
                            bool nonBlock, unsigned long tail,
                            unsigned int logMask, pid_t pid,
-                           uint64_t start)
-        : mRefCount(1)
-        , mRelease(false)
-        , mError(false)
-        , threadRunning(false)
-        , mReader(reader)
-        , mLogMask(logMask)
-        , mPid(pid)
-        , mCount(0)
-        , mTail(tail)
-        , mIndex(0)
-        , mClient(client)
-        , mStart(start)
-        , mNonBlock(nonBlock)
-        , mEnd(LogBufferElement::getCurrentSequence())
-{
-        pthread_cond_init(&threadTriggeredCondition, NULL);
-        cleanSkip_Locked();
+                           uint64_t start) :
+        mRefCount(1),
+        mRelease(false),
+        mError(false),
+        threadRunning(false),
+        mReader(reader),
+        mLogMask(logMask),
+        mPid(pid),
+        mCount(0),
+        mTail(tail),
+        mIndex(0),
+        mClient(client),
+        mStart(start),
+        mNonBlock(nonBlock),
+        mEnd(LogBufferElement::getCurrentSequence()) {
+    pthread_cond_init(&threadTriggeredCondition, NULL);
+    cleanSkip_Locked();
 }
 
 void LogTimeEntry::startReader_Locked(void) {
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
index bee940d..277b3ca 100644
--- a/logd/LogWhiteBlackList.cpp
+++ b/logd/LogWhiteBlackList.cpp
@@ -22,10 +22,8 @@
 
 // White and Black list
 
-Prune::Prune(uid_t uid, pid_t pid)
-        : mUid(uid)
-        , mPid(pid)
-{ }
+Prune::Prune(uid_t uid, pid_t pid) : mUid(uid), mPid(pid) {
+}
 
 int Prune::cmp(uid_t uid, pid_t pid) const {
     if ((mUid == uid_all) || (mUid == uid)) {
@@ -51,8 +49,7 @@
     }
 }
 
-PruneList::PruneList()
-        : mWorstUidEnabled(true) {
+PruneList::PruneList() : mWorstUidEnabled(true) {
     mNaughty.clear();
     mNice.clear();
 }
diff --git a/logd/README.property b/logd/README.property
index 60542b2..ad7d0cd 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -4,9 +4,12 @@
 logd.auditd                 bool  true   Enable selinux audit daemon
 logd.auditd.dmesg           bool  true   selinux audit messages duplicated and
                                          sent on to dmesg log
+logd.klogd                  bool depends Enable klogd daemon
 logd.statistics             bool depends Enable logcat -S statistics.
-ro.config.low_ram           bool  false  if true, logd.statistics default false
-ro.build.type               string       if user, logd.statistics default false
+ro.config.low_ram           bool  false  if true, logd.statistics & logd.klogd
+                                         default false
+ro.build.type               string       if user, logd.statistics & logd.klogd
+                                         default false
 persist.logd.size          number 256K   default size of the buffer for all
                                          log ids at initial startup, at runtime
                                          use: logcat -b all -G <value>
diff --git a/logd/main.cpp b/logd/main.cpp
index 237c7c1..6db819e 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -35,12 +35,14 @@
 #include <cutils/properties.h>
 #include <cutils/sched_policy.h>
 #include <cutils/sockets.h>
+#include <log/event_tag_map.h>
 #include <private/android_filesystem_config.h>
 
 #include "CommandListener.h"
 #include "LogBuffer.h"
 #include "LogListener.h"
 #include "LogAudit.h"
+#include "LogKlog.h"
 
 #define KMSG_PRIORITY(PRI)                            \
     '<',                                              \
@@ -238,6 +240,34 @@
     sem_post(&reinit);
 }
 
+// tagToName converts an events tag into a name
+const char *android::tagToName(uint32_t tag) {
+    static const EventTagMap *map;
+
+    if (!map) {
+        sem_wait(&sem_name);
+        if (!map) {
+            map = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+        }
+        sem_post(&sem_name);
+        if (!map) {
+            return NULL;
+        }
+    }
+    return android_lookupEventTag(map, tag);
+}
+
+static bool property_get_bool_svelte(const char *key) {
+    bool not_user;
+    {
+        char property[PROPERTY_VALUE_MAX];
+        property_get("ro.build.type", property, "");
+        not_user = !!strcmp(property, "user");
+    }
+    return property_get_bool(key, not_user
+            && !property_get_bool("ro.config.low_ram", false));
+}
+
 // Foreground waits for exit of the main persistent threads
 // that are started here. The threads are created to manage
 // UNIX domain client sockets for writing, reading and
@@ -245,6 +275,11 @@
 // logging plugins like auditd and restart control. Additional
 // transitory per-client threads are created for each reader.
 int main(int argc, char *argv[]) {
+    int fdPmesg = -1;
+    bool klogd = property_get_bool_svelte("logd.klogd");
+    if (klogd) {
+        fdPmesg = open("/proc/kmsg", O_RDONLY | O_NDELAY);
+    }
     fdDmesg = open("/dev/kmsg", O_WRONLY);
 
     // issue reinit command. KISS argument parsing.
@@ -321,14 +356,8 @@
 
     signal(SIGHUP, reinit_signal_handler);
 
-    {
-        char property[PROPERTY_VALUE_MAX];
-        property_get("ro.build.type", property, "");
-        if (property_get_bool("logd.statistics",
-                   !!strcmp(property, "user")
-                && !property_get_bool("ro.config.low_ram", false))) {
-            logBuf->enableStatistics();
-        }
+    if (property_get_bool_svelte("logd.statistics")) {
+        logBuf->enableStatistics();
     }
 
     // LogReader listens on /dev/socket/logdr. When a client
@@ -363,12 +392,18 @@
 
     bool auditd = property_get_bool("logd.auditd", true);
 
+    LogAudit *al = NULL;
     if (auditd) {
         bool dmesg = property_get_bool("logd.auditd.dmesg", true);
+        al = new LogAudit(logBuf, reader, dmesg ? fdDmesg : -1);
+    }
 
-        // failure is an option ... messages are in dmesg (required by standard)
-        LogAudit *al = new LogAudit(logBuf, reader, dmesg ? fdDmesg : -1);
+    LogKlog *kl = NULL;
+    if (klogd) {
+        kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, al != NULL);
+    }
 
+    if (al || kl) {
         int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
         if (len > 0) {
             len++;
@@ -376,16 +411,31 @@
 
             int rc = klogctl(KLOG_READ_ALL, buf, len);
 
-            if (rc >= 0) {
-                buf[len - 1] = '\0';
+            buf[len - 1] = '\0';
 
-                for (char *ptr, *tok = buf; (tok = strtok_r(tok, "\r\n", &ptr)); tok = NULL) {
-                    al->log(tok);
+            if ((rc >= 0) && kl) {
+                kl->synchronize(buf);
+            }
+
+            for (char *ptr, *tok = buf;
+                 (rc >= 0) && ((tok = strtok_r(tok, "\r\n", &ptr)));
+                 tok = NULL) {
+                if (al) {
+                    rc = al->log(tok);
+                }
+                if (kl) {
+                    rc = kl->log(tok);
                 }
             }
         }
 
-        if (al->startListener()) {
+        // failure is an option ... messages are in dmesg (required by standard)
+
+        if (kl && kl->startListener()) {
+            delete kl;
+        }
+
+        if (al && al->startListener()) {
             delete al;
         }
     }
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 9cf9ed9..b735dc3 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -95,3 +95,6 @@
 /sys/devices/virtual/usb_composite/*   enable      0664  root   system
 /sys/devices/system/cpu/cpu*   cpufreq/scaling_max_freq   0664  system system
 /sys/devices/system/cpu/cpu*   cpufreq/scaling_min_freq   0664  system system
+
+# DVB API device nodes
+/dev/dvb*                 0660   root       system