Merge "Snapshot merge progress percentage"
diff --git a/adb/Android.bp b/adb/Android.bp
index bd1f124..3e8da8a 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -217,6 +217,7 @@
         "libcutils",
         "libcrypto_utils",
         "libcrypto",
+        "liblog",
         "libmdnssd",
         "libdiagnose_usb",
         "libusb",
diff --git a/base/Android.bp b/base/Android.bp
index 8351461..b25d0df 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -56,6 +56,7 @@
         "chrono_utils.cpp",
         "cmsg.cpp",
         "file.cpp",
+        "liblog_symbols.cpp",
         "logging.cpp",
         "mapped_file.cpp",
         "parsebool.cpp",
@@ -68,6 +69,10 @@
         "test_utils.cpp",
     ],
 
+    static: {
+        cflags: ["-DNO_LIBLOG_DLSYM"],
+    },
+
     cppflags: ["-Wexit-time-destructors"],
     shared_libs: ["liblog"],
     target: {
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index d099e52..077988e 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -85,7 +85,7 @@
   INFO,
   WARNING,
   ERROR,
-  FATAL_WITHOUT_ABORT,
+  FATAL_WITHOUT_ABORT,  // For loggability tests, this is considered identical to FATAL.
   FATAL,
 };
 
@@ -93,6 +93,8 @@
   DEFAULT,
   MAIN,
   SYSTEM,
+  RADIO,
+  CRASH,
 };
 
 using LogFunction = std::function<void(LogId, LogSeverity, const char*, const char*,
@@ -116,7 +118,6 @@
 std::string GetDefaultTag();
 void SetDefaultTag(const std::string& tag);
 
-#ifdef __ANDROID__
 // We expose this even though it is the default because a user that wants to
 // override the default log buffer will have to construct this themselves.
 class LogdLogger {
@@ -129,7 +130,6 @@
  private:
   LogId default_log_id_;
 };
-#endif
 
 // Configure logging based on ANDROID_LOG_TAGS environment variable.
 // We need to parse a string that looks like
@@ -211,8 +211,8 @@
 #define ABORT_AFTER_LOG_FATAL_EXPR(x) ABORT_AFTER_LOG_EXPR_IF(true, x)
 
 // Defines whether the given severity will be logged or silently swallowed.
-#define WOULD_LOG(severity) \
-  (UNLIKELY((SEVERITY_LAMBDA(severity)) >= ::android::base::GetMinimumLogSeverity()) || \
+#define WOULD_LOG(severity)                                                              \
+  (UNLIKELY(::android::base::ShouldLog(SEVERITY_LAMBDA(severity), _LOG_TAG_INTERNAL)) || \
    MUST_LOG_MESSAGE(severity))
 
 // Get an ostream that can be used for logging at the given severity and to the default
@@ -444,6 +444,9 @@
 // Set the minimum severity level for logging, returning the old severity.
 LogSeverity SetMinimumLogSeverity(LogSeverity new_severity);
 
+// Return whether or not a log message with the associated tag should be logged.
+bool ShouldLog(LogSeverity severity, const char* tag);
+
 // Allows to temporarily change the minimum severity level for logging.
 class ScopedLogSeverity {
  public:
diff --git a/base/liblog_symbols.cpp b/base/liblog_symbols.cpp
new file mode 100644
index 0000000..d0e2eaa
--- /dev/null
+++ b/base/liblog_symbols.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 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 "liblog_symbols.h"
+
+#if defined(__ANDROID__) && !defined(NO_LIBLOG_DLSYM)
+#include <dlfcn.h>
+#endif
+
+namespace android {
+namespace base {
+
+#if defined(__ANDROID__) && !defined(NO_LIBLOG_DLSYM)
+
+const std::optional<LibLogFunctions>& GetLibLogFunctions() {
+  static std::optional<LibLogFunctions> liblog_functions = []() -> std::optional<LibLogFunctions> {
+    void* liblog_handle = dlopen("liblog.so", RTLD_NOW);
+    if (liblog_handle == nullptr) {
+      return {};
+    }
+
+    LibLogFunctions real_liblog_functions = {};
+
+#define DLSYM(name)                                                                   \
+  real_liblog_functions.name =                                                        \
+      reinterpret_cast<decltype(LibLogFunctions::name)>(dlsym(liblog_handle, #name)); \
+  if (real_liblog_functions.name == nullptr) {                                        \
+    return {};                                                                        \
+  }
+
+    DLSYM(__android_log_set_logger)
+    DLSYM(__android_log_write_logger_data)
+    DLSYM(__android_log_logd_logger)
+    DLSYM(__android_log_stderr_logger)
+    DLSYM(__android_log_set_aborter)
+    DLSYM(__android_log_call_aborter)
+    DLSYM(__android_log_default_aborter)
+    DLSYM(__android_log_set_minimum_priority);
+    DLSYM(__android_log_get_minimum_priority);
+#undef DLSYM
+
+    return real_liblog_functions;
+  }();
+
+  return liblog_functions;
+}
+
+#else
+
+const std::optional<LibLogFunctions>& GetLibLogFunctions() {
+  static std::optional<LibLogFunctions> liblog_functions = []() -> std::optional<LibLogFunctions> {
+    return LibLogFunctions{
+        .__android_log_set_logger = __android_log_set_logger,
+        .__android_log_write_logger_data = __android_log_write_logger_data,
+        .__android_log_logd_logger = __android_log_logd_logger,
+        .__android_log_stderr_logger = __android_log_stderr_logger,
+        .__android_log_set_aborter = __android_log_set_aborter,
+        .__android_log_call_aborter = __android_log_call_aborter,
+        .__android_log_default_aborter = __android_log_default_aborter,
+        .__android_log_set_minimum_priority = __android_log_set_minimum_priority,
+        .__android_log_get_minimum_priority = __android_log_get_minimum_priority,
+    };
+  }();
+  return liblog_functions;
+}
+
+#endif
+
+}  // namespace base
+}  // namespace android
diff --git a/base/liblog_symbols.h b/base/liblog_symbols.h
new file mode 100644
index 0000000..c68fff6
--- /dev/null
+++ b/base/liblog_symbols.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <optional>
+
+#include <android/log.h>
+
+namespace android {
+namespace base {
+
+struct LibLogFunctions {
+  void (*__android_log_set_logger)(__android_logger_function logger);
+  void (*__android_log_write_logger_data)(struct __android_logger_data* logger_data,
+                                          const char* msg);
+
+  void (*__android_log_logd_logger)(const struct __android_logger_data* logger_data,
+                                    const char* msg);
+  void (*__android_log_stderr_logger)(const struct __android_logger_data* logger_data,
+                                      const char* message);
+
+  void (*__android_log_set_aborter)(__android_aborter_function aborter);
+  void (*__android_log_call_aborter)(const char* abort_message);
+  void (*__android_log_default_aborter)(const char* abort_message);
+  int (*__android_log_set_minimum_priority)(int priority);
+  int (*__android_log_get_minimum_priority)();
+};
+
+const std::optional<LibLogFunctions>& GetLibLogFunctions();
+
+}  // namespace base
+}  // namespace android
diff --git a/base/logging.cpp b/base/logging.cpp
index 598a522..508871d 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -36,17 +36,18 @@
 #include <sys/uio.h>
 #endif
 
+#include <atomic>
 #include <iostream>
 #include <limits>
 #include <mutex>
+#include <optional>
 #include <sstream>
 #include <string>
 #include <utility>
 #include <vector>
 
-// Headers for LogMessage::LogLine.
-#ifdef __ANDROID__
 #include <android/log.h>
+#ifdef __ANDROID__
 #include <android/set_abort_message.h>
 #else
 #include <sys/types.h>
@@ -59,6 +60,8 @@
 #include <android-base/strings.h>
 #include <android-base/threads.h>
 
+#include "liblog_symbols.h"
+
 namespace android {
 namespace base {
 
@@ -115,11 +118,84 @@
 }
 #endif
 
+static LogId log_id_tToLogId(int buffer_id) {
+  switch (buffer_id) {
+    case LOG_ID_MAIN:
+      return MAIN;
+    case LOG_ID_SYSTEM:
+      return SYSTEM;
+    case LOG_ID_RADIO:
+      return RADIO;
+    case LOG_ID_CRASH:
+      return CRASH;
+    case LOG_ID_DEFAULT:
+    default:
+      return DEFAULT;
+  }
+}
+
+static int LogIdTolog_id_t(LogId log_id) {
+  switch (log_id) {
+    case MAIN:
+      return LOG_ID_MAIN;
+    case SYSTEM:
+      return LOG_ID_SYSTEM;
+    case RADIO:
+      return LOG_ID_RADIO;
+    case CRASH:
+      return LOG_ID_CRASH;
+    case DEFAULT:
+    default:
+      return LOG_ID_DEFAULT;
+  }
+}
+
+static LogSeverity PriorityToLogSeverity(int priority) {
+  switch (priority) {
+    case ANDROID_LOG_DEFAULT:
+      return INFO;
+    case ANDROID_LOG_VERBOSE:
+      return VERBOSE;
+    case ANDROID_LOG_DEBUG:
+      return DEBUG;
+    case ANDROID_LOG_INFO:
+      return INFO;
+    case ANDROID_LOG_WARN:
+      return WARNING;
+    case ANDROID_LOG_ERROR:
+      return ERROR;
+    case ANDROID_LOG_FATAL:
+      return FATAL;
+    default:
+      return FATAL;
+  }
+}
+
+static android_LogPriority LogSeverityToPriority(LogSeverity severity) {
+  switch (severity) {
+    case VERBOSE:
+      return ANDROID_LOG_VERBOSE;
+    case DEBUG:
+      return ANDROID_LOG_DEBUG;
+    case INFO:
+      return ANDROID_LOG_INFO;
+    case WARNING:
+      return ANDROID_LOG_WARN;
+    case ERROR:
+      return ANDROID_LOG_ERROR;
+    case FATAL_WITHOUT_ABORT:
+    case FATAL:
+    default:
+      return ANDROID_LOG_FATAL;
+  }
+}
+
 static std::mutex& LoggingLock() {
   static auto& logging_lock = *new std::mutex();
   return logging_lock;
 }
 
+// Only used for Q fallback.
 static LogFunction& Logger() {
 #ifdef __ANDROID__
   static auto& logger = *new LogFunction(LogdLogger());
@@ -129,6 +205,7 @@
   return logger;
 }
 
+// Only used for Q fallback.
 static AbortFunction& Aborter() {
   static auto& aborter = *new AbortFunction(DefaultAborter);
   return aborter;
@@ -158,6 +235,8 @@
 }
 
 static bool gInitialized = false;
+
+// Only used for Q fallback.
 static LogSeverity gMinimumLogSeverity = INFO;
 
 #if defined(__linux__)
@@ -218,8 +297,13 @@
   static_assert(arraysize(log_characters) - 1 == FATAL + 1,
                 "Mismatch in size of log_characters and values in LogSeverity");
   char severity_char = log_characters[severity];
-  fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s:%u] %s\n", tag ? tag : "nullptr", severity_char,
-          timestamp, getpid(), GetThreadId(), file, line, message);
+  if (file != nullptr) {
+    fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s:%u] %s\n", tag ? tag : "nullptr", severity_char,
+            timestamp, getpid(), GetThreadId(), file, line, message);
+  } else {
+    fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s\n", tag ? tag : "nullptr", severity_char,
+            timestamp, getpid(), GetThreadId(), message);
+  }
 }
 
 void StdioLogger(LogId, LogSeverity severity, const char* /*tag*/, const char* /*file*/,
@@ -242,41 +326,35 @@
 }
 
 
-#ifdef __ANDROID__
 LogdLogger::LogdLogger(LogId default_log_id) : default_log_id_(default_log_id) {
 }
 
 void LogdLogger::operator()(LogId id, LogSeverity severity, const char* tag,
                             const char* file, unsigned int line,
                             const char* message) {
-  static constexpr android_LogPriority kLogSeverityToAndroidLogPriority[] = {
-      ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO,
-      ANDROID_LOG_WARN,    ANDROID_LOG_ERROR, ANDROID_LOG_FATAL,
-      ANDROID_LOG_FATAL,
-  };
-  static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1,
-                "Mismatch in size of kLogSeverityToAndroidLogPriority and values in LogSeverity");
-
-  int priority = kLogSeverityToAndroidLogPriority[severity];
+  android_LogPriority priority = LogSeverityToPriority(severity);
   if (id == DEFAULT) {
     id = default_log_id_;
   }
 
-  static constexpr log_id kLogIdToAndroidLogId[] = {
-    LOG_ID_MAX, LOG_ID_MAIN, LOG_ID_SYSTEM,
-  };
-  static_assert(arraysize(kLogIdToAndroidLogId) == SYSTEM + 1,
-                "Mismatch in size of kLogIdToAndroidLogId and values in LogId");
-  log_id lg_id = kLogIdToAndroidLogId[id];
+  int lg_id = LogIdTolog_id_t(id);
 
-  if (priority == ANDROID_LOG_FATAL) {
-    __android_log_buf_print(lg_id, priority, tag, "%s:%u] %s", file, line,
-                            message);
+  char log_message[1024];
+  if (priority == ANDROID_LOG_FATAL && file != nullptr) {
+    snprintf(log_message, sizeof(log_message), "%s:%u] %s", file, line, message);
+  } else {
+    snprintf(log_message, sizeof(log_message), "%s", message);
+  }
+
+  static auto& liblog_functions = GetLibLogFunctions();
+  if (liblog_functions) {
+    __android_logger_data logger_data = {sizeof(__android_logger_data),     lg_id, priority, tag,
+                                         static_cast<const char*>(nullptr), 0};
+    liblog_functions->__android_log_logd_logger(&logger_data, log_message);
   } else {
     __android_log_buf_print(lg_id, priority, tag, "%s", message);
   }
 }
-#endif
 
 void InitLogging(char* argv[], LogFunction&& logger, AbortFunction&& aborter) {
   SetLogger(std::forward<LogFunction>(logger));
@@ -307,27 +385,27 @@
     if (spec.size() == 3 && StartsWith(spec, "*:")) {
       switch (spec[2]) {
         case 'v':
-          gMinimumLogSeverity = VERBOSE;
+          SetMinimumLogSeverity(VERBOSE);
           continue;
         case 'd':
-          gMinimumLogSeverity = DEBUG;
+          SetMinimumLogSeverity(DEBUG);
           continue;
         case 'i':
-          gMinimumLogSeverity = INFO;
+          SetMinimumLogSeverity(INFO);
           continue;
         case 'w':
-          gMinimumLogSeverity = WARNING;
+          SetMinimumLogSeverity(WARNING);
           continue;
         case 'e':
-          gMinimumLogSeverity = ERROR;
+          SetMinimumLogSeverity(ERROR);
           continue;
         case 'f':
-          gMinimumLogSeverity = FATAL_WITHOUT_ABORT;
+          SetMinimumLogSeverity(FATAL_WITHOUT_ABORT);
           continue;
         // liblog will even suppress FATAL if you say 's' for silent, but that's
         // crazy!
         case 's':
-          gMinimumLogSeverity = FATAL_WITHOUT_ABORT;
+          SetMinimumLogSeverity(FATAL_WITHOUT_ABORT);
           continue;
       }
     }
@@ -337,13 +415,46 @@
 }
 
 void SetLogger(LogFunction&& logger) {
-  std::lock_guard<std::mutex> lock(LoggingLock());
-  Logger() = std::move(logger);
+  static auto& liblog_functions = GetLibLogFunctions();
+  if (liblog_functions) {
+    // We need to atomically swap the old and new pointers since other threads may be logging.
+    // We know all threads will be using the new logger after __android_log_set_logger() returns,
+    // so we can delete it then.
+    // This leaks one std::function<> per instance of libbase if multiple copies of libbase within a
+    // single process call SetLogger().  That is the same cost as having a static
+    // std::function<>, which is the not-thread-safe alternative.
+    static std::atomic<LogFunction*> logger_function(nullptr);
+    auto* old_logger_function = logger_function.exchange(new LogFunction(logger));
+    liblog_functions->__android_log_set_logger([](const struct __android_logger_data* logger_data,
+                                                  const char* message) {
+      auto log_id = log_id_tToLogId(logger_data->buffer_id);
+      auto severity = PriorityToLogSeverity(logger_data->priority);
+
+      auto& function = *logger_function.load(std::memory_order_acquire);
+      function(log_id, severity, logger_data->tag, logger_data->file, logger_data->line, message);
+    });
+    delete old_logger_function;
+  } else {
+    std::lock_guard<std::mutex> lock(LoggingLock());
+    Logger() = std::move(logger);
+  }
 }
 
 void SetAborter(AbortFunction&& aborter) {
-  std::lock_guard<std::mutex> lock(LoggingLock());
-  Aborter() = std::move(aborter);
+  static auto& liblog_functions = GetLibLogFunctions();
+  if (liblog_functions) {
+    // See the comment in SetLogger().
+    static std::atomic<AbortFunction*> abort_function(nullptr);
+    auto* old_abort_function = abort_function.exchange(new AbortFunction(aborter));
+    __android_log_set_aborter([](const char* abort_message) {
+      auto& function = *abort_function.load(std::memory_order_acquire);
+      function(abort_message);
+    });
+    delete old_abort_function;
+  } else {
+    std::lock_guard<std::mutex> lock(LoggingLock());
+    Aborter() = std::move(aborter);
+  }
 }
 
 // This indirection greatly reduces the stack impact of having lots of
@@ -446,7 +557,12 @@
 
   // Abort if necessary.
   if (data_->GetSeverity() == FATAL) {
-    Aborter()(msg.c_str());
+    static auto& liblog_functions = GetLibLogFunctions();
+    if (liblog_functions) {
+      liblog_functions->__android_log_call_aborter(msg.c_str());
+    } else {
+      Aborter()(msg.c_str());
+    }
   }
 }
 
@@ -456,25 +572,65 @@
 
 void LogMessage::LogLine(const char* file, unsigned int line, LogSeverity severity, const char* tag,
                          const char* message) {
+  static auto& liblog_functions = GetLibLogFunctions();
+  auto priority = LogSeverityToPriority(severity);
   if (tag == nullptr) {
     std::lock_guard<std::recursive_mutex> lock(TagLock());
     if (gDefaultTag == nullptr) {
       gDefaultTag = new std::string(getprogname());
     }
-    Logger()(DEFAULT, severity, gDefaultTag->c_str(), file, line, message);
+
+    if (liblog_functions) {
+      __android_logger_data logger_data = {sizeof(__android_logger_data), LOG_ID_DEFAULT, priority,
+                                           gDefaultTag->c_str(),          file,           line};
+      __android_log_write_logger_data(&logger_data, message);
+    } else {
+      Logger()(DEFAULT, severity, gDefaultTag->c_str(), file, line, message);
+    }
   } else {
-    Logger()(DEFAULT, severity, tag, file, line, message);
+    if (liblog_functions) {
+      __android_logger_data logger_data = {
+          sizeof(__android_logger_data), LOG_ID_DEFAULT, priority, tag, file, line};
+      __android_log_write_logger_data(&logger_data, message);
+    } else {
+      Logger()(DEFAULT, severity, tag, file, line, message);
+    }
   }
 }
 
 LogSeverity GetMinimumLogSeverity() {
+  static auto& liblog_functions = GetLibLogFunctions();
+  if (liblog_functions) {
+    return PriorityToLogSeverity(liblog_functions->__android_log_get_minimum_priority());
+  } else {
     return gMinimumLogSeverity;
+  }
+}
+
+bool ShouldLog(LogSeverity severity, const char* tag) {
+  static auto& liblog_functions = GetLibLogFunctions();
+  // Even though we're not using the R liblog functions in this function, if we're running on Q,
+  // we need to fall back to using gMinimumLogSeverity, since __android_log_is_loggable() will not
+  // take into consideration the value from SetMinimumLogSeverity().
+  if (liblog_functions) {
+    // TODO: It is safe to pass nullptr for tag, but it will be better to use the default log tag.
+    int priority = LogSeverityToPriority(severity);
+    return __android_log_is_loggable(priority, tag, ANDROID_LOG_INFO);
+  } else {
+    return severity >= gMinimumLogSeverity;
+  }
 }
 
 LogSeverity SetMinimumLogSeverity(LogSeverity new_severity) {
-  LogSeverity old_severity = gMinimumLogSeverity;
-  gMinimumLogSeverity = new_severity;
-  return old_severity;
+  static auto& liblog_functions = GetLibLogFunctions();
+  if (liblog_functions) {
+    auto priority = LogSeverityToPriority(new_severity);
+    return PriorityToLogSeverity(liblog_functions->__android_log_set_minimum_priority(priority));
+  } else {
+    LogSeverity old_severity = gMinimumLogSeverity;
+    gMinimumLogSeverity = new_severity;
+    return old_severity;
+  }
 }
 
 ScopedLogSeverity::ScopedLogSeverity(LogSeverity new_severity) {
diff --git a/base/logging_test.cpp b/base/logging_test.cpp
index 3113fb4..8f46196 100644
--- a/base/logging_test.cpp
+++ b/base/logging_test.cpp
@@ -140,10 +140,6 @@
   CHECK_WOULD_LOG_ENABLED(FATAL);
 }
 
-TEST(logging, WOULD_LOG_FATAL_WITHOUT_ABORT_disabled) {
-  CHECK_WOULD_LOG_DISABLED(FATAL_WITHOUT_ABORT);
-}
-
 TEST(logging, WOULD_LOG_FATAL_WITHOUT_ABORT_enabled) {
   CHECK_WOULD_LOG_ENABLED(FATAL_WITHOUT_ABORT);
 }
@@ -266,10 +262,6 @@
     CheckMessage(cap2, android::base::severity, "foobar"); \
   } \
 
-TEST(logging, LOG_STREAM_FATAL_WITHOUT_ABORT_disabled) {
-  CHECK_LOG_STREAM_DISABLED(FATAL_WITHOUT_ABORT);
-}
-
 TEST(logging, LOG_STREAM_FATAL_WITHOUT_ABORT_enabled) {
   ASSERT_NO_FATAL_FAILURE(CHECK_LOG_STREAM_ENABLED(FATAL_WITHOUT_ABORT));
 }
@@ -352,10 +344,6 @@
   ASSERT_DEATH({SuppressAbortUI(); LOG(::android::base::FATAL) << "foobar";}, "foobar");
 }
 
-TEST(logging, LOG_FATAL_WITHOUT_ABORT_disabled) {
-  CHECK_LOG_DISABLED(FATAL_WITHOUT_ABORT);
-}
-
 TEST(logging, LOG_FATAL_WITHOUT_ABORT_enabled) {
   ASSERT_NO_FATAL_FAILURE(CHECK_LOG_ENABLED(FATAL_WITHOUT_ABORT));
 }
@@ -508,10 +496,6 @@
   ASSERT_DEATH({SuppressAbortUI(); PLOG(::android::base::FATAL) << "foobar";}, "foobar");
 }
 
-TEST(logging, PLOG_FATAL_WITHOUT_ABORT_disabled) {
-  CHECK_PLOG_DISABLED(FATAL_WITHOUT_ABORT);
-}
-
 TEST(logging, PLOG_FATAL_WITHOUT_ABORT_enabled) {
   ASSERT_NO_FATAL_FAILURE(CHECK_PLOG_ENABLED(FATAL_WITHOUT_ABORT));
 }
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
index 8979b0c..f379d76 100755
--- a/bootstat/boot_reason_test.sh
+++ b/bootstat/boot_reason_test.sh
@@ -636,7 +636,7 @@
   rm -r ${ANDROID_PRODUCT_OUT}/obj/ETC/system_build_prop_intermediates ||
     true
   pushd ${ANDROID_BUILD_TOP} >&2
-  make -j50 >&2
+  build/soong/soong_ui.bash --make-mode >&2
   if [ ${?} != 0 ]; then
     popd >&2
     return 1
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 6e01289..f8192b5 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -592,19 +592,20 @@
     g_callbacks = *callbacks;
   }
 
-  void* thread_stack_allocation =
-    mmap(nullptr, PAGE_SIZE * 3, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+  size_t thread_stack_pages = 8;
+  void* thread_stack_allocation = mmap(nullptr, PAGE_SIZE * (thread_stack_pages + 2), PROT_NONE,
+                                       MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
   if (thread_stack_allocation == MAP_FAILED) {
     fatal_errno("failed to allocate debuggerd thread stack");
   }
 
   char* stack = static_cast<char*>(thread_stack_allocation) + PAGE_SIZE;
-  if (mprotect(stack, PAGE_SIZE, PROT_READ | PROT_WRITE) != 0) {
+  if (mprotect(stack, PAGE_SIZE * thread_stack_pages, PROT_READ | PROT_WRITE) != 0) {
     fatal_errno("failed to mprotect debuggerd thread stack");
   }
 
   // Stack grows negatively, set it to the last byte in the page...
-  stack = (stack + PAGE_SIZE - 1);
+  stack = (stack + thread_stack_pages * PAGE_SIZE - 1);
   // and align it.
   stack -= 15;
   pseudothread_stack = stack;
diff --git a/fastboot/device/usb_client.cpp b/fastboot/device/usb_client.cpp
index 5066046..9c80765 100644
--- a/fastboot/device/usb_client.cpp
+++ b/fastboot/device/usb_client.cpp
@@ -297,3 +297,7 @@
     CloseFunctionFs(handle_.get());
     return 0;
 }
+
+int ClientUsbTransport::Reset() {
+    return 0;
+}
diff --git a/fastboot/device/usb_client.h b/fastboot/device/usb_client.h
index 3694f9a..e6a1a8b 100644
--- a/fastboot/device/usb_client.h
+++ b/fastboot/device/usb_client.h
@@ -29,6 +29,7 @@
     ssize_t Read(void* data, size_t len) override;
     ssize_t Write(const void* data, size_t len) override;
     int Close() override;
+    int Reset() override;
 
   private:
     std::unique_ptr<usb_handle> handle_;
diff --git a/fastboot/fuzzy_fastboot/Android.bp b/fastboot/fuzzy_fastboot/Android.bp
index d48cfa9..bb54fd9 100644
--- a/fastboot/fuzzy_fastboot/Android.bp
+++ b/fastboot/fuzzy_fastboot/Android.bp
@@ -5,7 +5,7 @@
   srcs: [
     "main.cpp",
     "extensions.cpp",
-    "usb_transport_sniffer.cpp",
+    "transport_sniffer.cpp",
     "fixtures.cpp",
     "test_utils.cpp",
   ],
diff --git a/fastboot/fuzzy_fastboot/fixtures.cpp b/fastboot/fuzzy_fastboot/fixtures.cpp
index bc13a8c..bd76ff4 100644
--- a/fastboot/fuzzy_fastboot/fixtures.cpp
+++ b/fastboot/fuzzy_fastboot/fixtures.cpp
@@ -48,12 +48,13 @@
 #include <gtest/gtest.h>
 
 #include "fastboot_driver.h"
+#include "tcp.h"
 #include "usb.h"
 
 #include "extensions.h"
 #include "fixtures.h"
 #include "test_utils.h"
-#include "usb_transport_sniffer.h"
+#include "transport_sniffer.h"
 
 using namespace std::literals::chrono_literals;
 
@@ -74,7 +75,14 @@
     return 0;
 }
 
+bool FastBootTest::IsFastbootOverTcp() {
+    // serial contains ":" is treated as host ip and port number
+    return (device_serial.find(":") != std::string::npos);
+}
+
 bool FastBootTest::UsbStillAvailible() {
+    if (IsFastbootOverTcp()) return true;
+
     // For some reason someone decided to prefix the path with "usb:"
     std::string prefix("usb:");
     if (std::equal(prefix.begin(), prefix.end(), device_path.begin())) {
@@ -113,15 +121,19 @@
         ASSERT_TRUE(UsbStillAvailible());  // The device disconnected
     }
 
-    const auto matcher = [](usb_ifc_info* info) -> int {
-        return MatchFastboot(info, device_serial);
-    };
-    for (int i = 0; i < MAX_USB_TRIES && !transport; i++) {
-        std::unique_ptr<UsbTransport> usb(usb_open(matcher, USB_TIMEOUT));
-        if (usb)
-            transport = std::unique_ptr<UsbTransportSniffer>(
-                    new UsbTransportSniffer(std::move(usb), serial_port));
-        std::this_thread::sleep_for(std::chrono::milliseconds(10));
+    if (IsFastbootOverTcp()) {
+        ConnectTcpFastbootDevice();
+    } else {
+        const auto matcher = [](usb_ifc_info* info) -> int {
+            return MatchFastboot(info, device_serial);
+        };
+        for (int i = 0; i < MAX_USB_TRIES && !transport; i++) {
+            std::unique_ptr<UsbTransport> usb(usb_open(matcher, USB_TIMEOUT));
+            if (usb)
+                transport = std::unique_ptr<TransportSniffer>(
+                        new TransportSniffer(std::move(usb), serial_port));
+            std::this_thread::sleep_for(std::chrono::milliseconds(10));
+        }
     }
 
     ASSERT_TRUE(transport);  // no nullptr
@@ -154,6 +166,8 @@
 
 // TODO, this should eventually be piped to a file instead of stdout
 void FastBootTest::TearDownSerial() {
+    if (IsFastbootOverTcp()) return;
+
     if (!transport) return;
     // One last read from serial
     transport->ProcessSerial();
@@ -167,9 +181,34 @@
     }
 }
 
+void FastBootTest::ConnectTcpFastbootDevice() {
+    std::size_t found = device_serial.find(":");
+    if (found != std::string::npos) {
+        for (int i = 0; i < MAX_TCP_TRIES && !transport; i++) {
+            std::string error;
+            std::unique_ptr<Transport> tcp(
+                    tcp::Connect(device_serial.substr(0, found), tcp::kDefaultPort, &error)
+                            .release());
+            if (tcp)
+                transport =
+                        std::unique_ptr<TransportSniffer>(new TransportSniffer(std::move(tcp), 0));
+            if (transport != nullptr) break;
+            std::this_thread::sleep_for(std::chrono::milliseconds(10));
+        }
+    }
+}
+
 void FastBootTest::ReconnectFastbootDevice() {
     fb.reset();
     transport.reset();
+
+    if (IsFastbootOverTcp()) {
+        ConnectTcpFastbootDevice();
+        device_path = cb_scratch;
+        fb = std::unique_ptr<FastBootDriver>(new FastBootDriver(transport.get(), {}, true));
+        return;
+    }
+
     while (UsbStillAvailible())
         ;
     printf("WAITING FOR DEVICE\n");
@@ -180,8 +219,8 @@
     while (!transport) {
         std::unique_ptr<UsbTransport> usb(usb_open(matcher, USB_TIMEOUT));
         if (usb) {
-            transport = std::unique_ptr<UsbTransportSniffer>(
-                    new UsbTransportSniffer(std::move(usb), serial_port));
+            transport = std::unique_ptr<TransportSniffer>(
+                    new TransportSniffer(std::move(usb), serial_port));
         }
         std::this_thread::sleep_for(1s);
     }
diff --git a/fastboot/fuzzy_fastboot/fixtures.h b/fastboot/fuzzy_fastboot/fixtures.h
index c71c897..2468868 100644
--- a/fastboot/fuzzy_fastboot/fixtures.h
+++ b/fastboot/fuzzy_fastboot/fixtures.h
@@ -31,7 +31,7 @@
 #include "fastboot_driver.h"
 
 #include "extensions.h"
-#include "usb_transport_sniffer.h"
+#include "transport_sniffer.h"
 
 namespace fastboot {
 
@@ -45,11 +45,14 @@
     static int serial_port;
     static std::string device_serial;
     static constexpr int MAX_USB_TRIES = 10;
+    static constexpr int MAX_TCP_TRIES = 6000;
 
     static int MatchFastboot(usb_ifc_info* info, const std::string& local_serial = "");
+    static bool IsFastbootOverTcp();
     bool UsbStillAvailible();
     bool UserSpaceFastboot();
     void ReconnectFastbootDevice();
+    void ConnectTcpFastbootDevice();
 
   protected:
     RetCode DownloadCommand(uint32_t size, std::string* response = nullptr,
@@ -64,7 +67,7 @@
     void TearDownSerial();
     void SetLockState(bool unlock, bool assert_change = true);
 
-    std::unique_ptr<UsbTransportSniffer> transport;
+    std::unique_ptr<TransportSniffer> transport;
     std::unique_ptr<FastBootDriver> fb;
 
   private:
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index a1d69d2..b9784fe 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -54,7 +54,7 @@
 #include "extensions.h"
 #include "fixtures.h"
 #include "test_utils.h"
-#include "usb_transport_sniffer.h"
+#include "transport_sniffer.h"
 
 namespace fastboot {
 
@@ -1756,16 +1756,19 @@
     }
 
     setbuf(stdout, NULL);  // no buffering
-    printf("<Waiting for Device>\n");
-    const auto matcher = [](usb_ifc_info* info) -> int {
-        return fastboot::FastBootTest::MatchFastboot(info, fastboot::FastBootTest::device_serial);
-    };
-    Transport* transport = nullptr;
-    while (!transport) {
-        transport = usb_open(matcher);
-        std::this_thread::sleep_for(std::chrono::milliseconds(10));
+
+    if (!fastboot::FastBootTest::IsFastbootOverTcp()) {
+        printf("<Waiting for Device>\n");
+        const auto matcher = [](usb_ifc_info* info) -> int {
+            return fastboot::FastBootTest::MatchFastboot(info, fastboot::FastBootTest::device_serial);
+        };
+        Transport* transport = nullptr;
+        while (!transport) {
+            transport = usb_open(matcher);
+            std::this_thread::sleep_for(std::chrono::milliseconds(10));
+        }
+        transport->Close();
     }
-    transport->Close();
 
     if (args.find("serial_port") != args.end()) {
         fastboot::FastBootTest::serial_port = fastboot::ConfigureSerial(args.at("serial_port"));
diff --git a/fastboot/fuzzy_fastboot/usb_transport_sniffer.cpp b/fastboot/fuzzy_fastboot/transport_sniffer.cpp
similarity index 91%
rename from fastboot/fuzzy_fastboot/usb_transport_sniffer.cpp
rename to fastboot/fuzzy_fastboot/transport_sniffer.cpp
index 7c595f4..b55ffd3 100644
--- a/fastboot/fuzzy_fastboot/usb_transport_sniffer.cpp
+++ b/fastboot/fuzzy_fastboot/transport_sniffer.cpp
@@ -1,4 +1,4 @@
-#include "usb_transport_sniffer.h"
+#include "transport_sniffer.h"
 #include <android-base/stringprintf.h>
 #include <sys/select.h>
 #include <sys/time.h>
@@ -8,15 +8,15 @@
 
 namespace fastboot {
 
-UsbTransportSniffer::UsbTransportSniffer(std::unique_ptr<UsbTransport> transport,
+TransportSniffer::TransportSniffer(std::unique_ptr<Transport> transport,
                                          const int serial_fd)
     : transport_(std::move(transport)), serial_fd_(serial_fd) {}
 
-UsbTransportSniffer::~UsbTransportSniffer() {
+TransportSniffer::~TransportSniffer() {
     Close();
 }
 
-ssize_t UsbTransportSniffer::Read(void* data, size_t len) {
+ssize_t TransportSniffer::Read(void* data, size_t len) {
     ProcessSerial();
 
     ssize_t ret = transport_->Read(data, len);
@@ -37,7 +37,7 @@
     return ret;
 }
 
-ssize_t UsbTransportSniffer::Write(const void* data, size_t len) {
+ssize_t TransportSniffer::Write(const void* data, size_t len) {
     ProcessSerial();
 
     size_t ret = transport_->Write(data, len);
@@ -58,11 +58,11 @@
     return ret;
 }
 
-int UsbTransportSniffer::Close() {
+int TransportSniffer::Close() {
     return transport_->Close();
 }
 
-int UsbTransportSniffer::Reset() {
+int TransportSniffer::Reset() {
     ProcessSerial();
     int ret = transport_->Reset();
     std::vector<char> buf;
@@ -72,7 +72,7 @@
     return ret;
 }
 
-const std::vector<UsbTransportSniffer::Event> UsbTransportSniffer::Transfers() {
+const std::vector<TransportSniffer::Event> TransportSniffer::Transfers() {
     return transfers_;
 }
 
@@ -81,7 +81,7 @@
  * the failure. This method will look through its log of captured events, and
  * create a clean printable string of everything that happened.
  */
-std::string UsbTransportSniffer::CreateTrace() {
+std::string TransportSniffer::CreateTrace() {
     std::string ret;
 
     const auto no_print = [](char c) -> bool { return !isprint(c); };
@@ -158,7 +158,7 @@
 
 // This is a quick call to flush any UART logs the device might have sent
 // to our internal event log. It will wait up to 10ms for data to appear
-void UsbTransportSniffer::ProcessSerial() {
+void TransportSniffer::ProcessSerial() {
     if (serial_fd_ <= 0) return;
 
     fd_set set;
diff --git a/fastboot/fuzzy_fastboot/usb_transport_sniffer.h b/fastboot/fuzzy_fastboot/transport_sniffer.h
similarity index 90%
rename from fastboot/fuzzy_fastboot/usb_transport_sniffer.h
rename to fastboot/fuzzy_fastboot/transport_sniffer.h
index 8119aea..2cbb9fe 100644
--- a/fastboot/fuzzy_fastboot/usb_transport_sniffer.h
+++ b/fastboot/fuzzy_fastboot/transport_sniffer.h
@@ -42,12 +42,12 @@
 /* A special class for sniffing reads and writes
  *
  * A useful debugging tool is to see the raw fastboot transactions going between
- * the host and device. This class wraps the UsbTransport class, and snoops and saves
+ * the host and device. This class is a special subclass of Transport that snoops and saves
  * all the transactions going on. Additionally, if there is a console serial port
  * from the device, this class can monitor it as well and capture the interleaving of
  * transport transactions and UART log messages.
  */
-class UsbTransportSniffer : public UsbTransport {
+class TransportSniffer : public Transport {
   public:
     enum EventType {
         READ,
@@ -67,8 +67,8 @@
         const std::vector<char> buf;
     };
 
-    UsbTransportSniffer(std::unique_ptr<UsbTransport> transport, const int serial_fd = 0);
-    ~UsbTransportSniffer() override;
+    TransportSniffer(std::unique_ptr<Transport> transport, const int serial_fd = 0);
+    ~TransportSniffer() override;
 
     virtual ssize_t Read(void* data, size_t len) override;
     virtual ssize_t Write(const void* data, size_t len) override;
@@ -81,7 +81,7 @@
 
   private:
     std::vector<Event> transfers_;
-    std::unique_ptr<UsbTransport> transport_;
+    std::unique_ptr<Transport> transport_;
     const int serial_fd_;
 };
 
diff --git a/fastboot/tcp.cpp b/fastboot/tcp.cpp
index dd6fbf8..dca306f 100644
--- a/fastboot/tcp.cpp
+++ b/fastboot/tcp.cpp
@@ -64,6 +64,7 @@
     ssize_t Read(void* data, size_t length) override;
     ssize_t Write(const void* data, size_t length) override;
     int Close() override;
+    int Reset() override;
 
   private:
     explicit TcpTransport(std::unique_ptr<Socket> sock) : socket_(std::move(sock)) {}
@@ -178,6 +179,10 @@
     return result;
 }
 
+int TcpTransport::Reset() {
+    return 0;
+}
+
 std::unique_ptr<Transport> Connect(const std::string& hostname, int port, std::string* error) {
     return internal::Connect(Socket::NewClient(Socket::Protocol::kTcp, hostname, port, error),
                              error);
diff --git a/fastboot/transport.h b/fastboot/transport.h
index 96b90d2..de0cc92 100644
--- a/fastboot/transport.h
+++ b/fastboot/transport.h
@@ -36,6 +36,8 @@
     // Closes the underlying transport. Returns 0 on success.
     virtual int Close() = 0;
 
+    virtual int Reset() = 0;
+
     // Blocks until the transport disconnects. Transports that don't support
     // this will return immediately. Returns 0 on success.
     virtual int WaitForDisconnect() { return 0; }
diff --git a/fastboot/udp.cpp b/fastboot/udp.cpp
index 53fb347..308c96c 100644
--- a/fastboot/udp.cpp
+++ b/fastboot/udp.cpp
@@ -109,6 +109,7 @@
     ssize_t Read(void* data, size_t length) override;
     ssize_t Write(const void* data, size_t length) override;
     int Close() override;
+    int Reset() override;
 
   private:
     explicit UdpTransport(std::unique_ptr<Socket> socket) : socket_(std::move(socket)) {}
@@ -370,6 +371,10 @@
     return result;
 }
 
+int UdpTransport::Reset() {
+    return 0;
+}
+
 std::unique_ptr<Transport> Connect(const std::string& hostname, int port, std::string* error) {
     return internal::Connect(Socket::NewClient(Socket::Protocol::kUdp, hostname, port, error),
                              error);
diff --git a/fs_mgr/libfiemap/image_manager.cpp b/fs_mgr/libfiemap/image_manager.cpp
index 30eb5a0..280318e 100644
--- a/fs_mgr/libfiemap/image_manager.cpp
+++ b/fs_mgr/libfiemap/image_manager.cpp
@@ -26,6 +26,7 @@
 #include <fs_mgr_dm_linear.h>
 #include <libdm/loop_control.h>
 #include <libfiemap/split_fiemap_writer.h>
+#include <libgsi/libgsi.h>
 
 #include "metadata.h"
 #include "utility.h"
@@ -34,6 +35,7 @@
 namespace fiemap {
 
 using namespace std::literals;
+using android::base::ReadFileToString;
 using android::base::unique_fd;
 using android::dm::DeviceMapper;
 using android::dm::DmDeviceState;
@@ -53,6 +55,11 @@
 std::unique_ptr<ImageManager> ImageManager::Open(const std::string& dir_prefix) {
     auto metadata_dir = "/metadata/gsi/" + dir_prefix;
     auto data_dir = "/data/gsi/" + dir_prefix;
+    auto install_dir_file = gsi::DsuInstallDirFile(gsi::GetDsuSlot(dir_prefix));
+    std::string path;
+    if (ReadFileToString(install_dir_file, &path)) {
+        data_dir = path;
+    }
     return Open(metadata_dir, data_dir);
 }
 
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 9e67c66..c67e33d 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -75,6 +75,7 @@
         "snapshot.cpp",
         "snapshot_metadata_updater.cpp",
         "partition_cow_creator.cpp",
+        "return.cpp",
         "utility.cpp",
     ],
 }
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/return.h b/fs_mgr/libsnapshot/include/libsnapshot/return.h
new file mode 100644
index 0000000..dedc445
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/return.h
@@ -0,0 +1,59 @@
+// Copyright (C) 2019 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.
+
+#pragma once
+
+#include <stdint.h>
+#include <string.h>
+
+#include <libfiemap/fiemap_status.h>
+
+namespace android::snapshot {
+
+// SnapshotManager functions return either bool or Return objects. "Return" types provides
+// more information about the reason of the failure.
+class Return {
+    using FiemapStatus = android::fiemap::FiemapStatus;
+
+  public:
+    enum class ErrorCode : int32_t {
+        SUCCESS = static_cast<int32_t>(FiemapStatus::ErrorCode::SUCCESS),
+        ERROR = static_cast<int32_t>(FiemapStatus::ErrorCode::ERROR),
+        NO_SPACE = static_cast<int32_t>(FiemapStatus::ErrorCode::NO_SPACE),
+    };
+    ErrorCode error_code() const { return error_code_; }
+    bool is_ok() const { return error_code() == ErrorCode::SUCCESS; }
+    operator bool() const { return is_ok(); }
+    // Total required size on /userdata.
+    uint64_t required_size() const { return required_size_; }
+    std::string string() const;
+
+    static Return Ok() { return Return(ErrorCode::SUCCESS); }
+    static Return Error() { return Return(ErrorCode::ERROR); }
+    static Return NoSpace(uint64_t size) { return Return(ErrorCode::NO_SPACE, size); }
+    // Does not set required_size_ properly even when status.error_code() == NO_SPACE.
+    explicit Return(const FiemapStatus& status)
+        : error_code_(FromFiemapStatusErrorCode(status.error_code())), required_size_(0) {}
+
+  private:
+    ErrorCode error_code_;
+    uint64_t required_size_;
+    Return(ErrorCode error_code, uint64_t required_size = 0)
+        : error_code_(error_code), required_size_(required_size) {}
+
+    // FiemapStatus::ErrorCode -> ErrorCode
+    static ErrorCode FromFiemapStatusErrorCode(FiemapStatus::ErrorCode error_code);
+};
+
+}  // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 61946f7..e503ec3 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -35,6 +35,7 @@
 #include <update_engine/update_metadata.pb.h>
 
 #include <libsnapshot/auto_device.h>
+#include <libsnapshot/return.h>
 
 #ifndef FRIEND_TEST
 #define FRIEND_TEST(test_set_name, individual_test) \
@@ -91,27 +92,6 @@
     using FiemapStatus = android::fiemap::FiemapStatus;
 
   public:
-    // SnapshotManager functions return either bool or Return objects. "Return" types provides
-    // more information about the reason of the failure.
-    class Return : public FiemapStatus {
-      public:
-        // Total required size on /userdata.
-        uint64_t required_size() const { return required_size_; }
-
-        static Return Ok() { return Return(FiemapStatus::ErrorCode::SUCCESS); }
-        static Return Error() { return Return(FiemapStatus::ErrorCode::ERROR); }
-        static Return NoSpace(uint64_t size) {
-            return Return(FiemapStatus::ErrorCode::NO_SPACE, size);
-        }
-        // Does not set required_size_ properly even when status.error_code() == NO_SPACE.
-        explicit Return(const FiemapStatus& status) : Return(status.error_code()) {}
-
-      private:
-        uint64_t required_size_;
-        Return(FiemapStatus::ErrorCode code, uint64_t required_size = 0)
-            : FiemapStatus(code), required_size_(required_size) {}
-    };
-
     // Dependency injection for testing.
     class IDeviceInfo {
       public:
diff --git a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
index 11de6ed..98bf56a 100644
--- a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
+++ b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
@@ -42,7 +42,6 @@
 using testing::_;
 using testing::AssertionResult;
 using testing::NiceMock;
-using testing::Return;
 
 using namespace android::storage_literals;
 using namespace std::string_literals;
@@ -117,6 +116,7 @@
 class SnapshotTestPropertyFetcher : public android::fs_mgr::testing::MockPropertyFetcher {
   public:
     SnapshotTestPropertyFetcher(const std::string& slot_suffix) {
+        using testing::Return;
         ON_CALL(*this, GetProperty("ro.boot.slot_suffix", _)).WillByDefault(Return(slot_suffix));
         ON_CALL(*this, GetBoolProperty("ro.boot.dynamic_partitions", _))
                 .WillByDefault(Return(true));
diff --git a/fs_mgr/libsnapshot/return.cpp b/fs_mgr/libsnapshot/return.cpp
new file mode 100644
index 0000000..cc64af5
--- /dev/null
+++ b/fs_mgr/libsnapshot/return.cpp
@@ -0,0 +1,44 @@
+// Copyright (C) 2019 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 <libsnapshot/return.h>
+
+#include <string.h>
+
+using android::fiemap::FiemapStatus;
+
+namespace android::snapshot {
+
+std::string Return::string() const {
+    switch (error_code()) {
+        case ErrorCode::ERROR:
+            return "Error";
+        case ErrorCode::SUCCESS:
+            [[fallthrough]];
+        case ErrorCode::NO_SPACE:
+            return strerror(-static_cast<int>(error_code()));
+    }
+}
+
+Return::ErrorCode Return::FromFiemapStatusErrorCode(FiemapStatus::ErrorCode error_code) {
+    switch (error_code) {
+        case FiemapStatus::ErrorCode::SUCCESS:
+        case FiemapStatus::ErrorCode::ERROR:
+        case FiemapStatus::ErrorCode::NO_SPACE:
+            return static_cast<ErrorCode>(error_code);
+        default:
+            return ErrorCode::ERROR;
+    }
+}
+}  // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index b84d873..c731cb0 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -290,7 +290,7 @@
     return true;
 }
 
-SnapshotManager::Return SnapshotManager::CreateCowImage(LockedFile* lock, const std::string& name) {
+Return SnapshotManager::CreateCowImage(LockedFile* lock, const std::string& name) {
     CHECK(lock);
     CHECK(lock->lock_mode() == LOCK_EX);
     if (!EnsureImageManager()) return Return::Error();
@@ -1920,21 +1920,19 @@
     }
 }
 
-static SnapshotManager::Return AddRequiredSpace(
-        SnapshotManager::Return orig,
-        const std::map<std::string, SnapshotStatus>& all_snapshot_status) {
-    if (orig.error_code() != SnapshotManager::Return::ErrorCode::NO_SPACE) {
+static Return AddRequiredSpace(Return orig,
+                               const std::map<std::string, SnapshotStatus>& all_snapshot_status) {
+    if (orig.error_code() != Return::ErrorCode::NO_SPACE) {
         return orig;
     }
     uint64_t sum = 0;
     for (auto&& [name, status] : all_snapshot_status) {
         sum += status.cow_file_size();
     }
-    return SnapshotManager::Return::NoSpace(sum);
+    return Return::NoSpace(sum);
 }
 
-SnapshotManager::Return SnapshotManager::CreateUpdateSnapshots(
-        const DeltaArchiveManifest& manifest) {
+Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manifest) {
     auto lock = LockExclusive();
     if (!lock) return Return::Error();
 
@@ -2028,7 +2026,7 @@
     return Return::Ok();
 }
 
-SnapshotManager::Return SnapshotManager::CreateUpdateSnapshotsInternal(
+Return SnapshotManager::CreateUpdateSnapshotsInternal(
         LockedFile* lock, const DeltaArchiveManifest& manifest, PartitionCowCreator* cow_creator,
         AutoDeviceList* created_devices,
         std::map<std::string, SnapshotStatus>* all_snapshot_status) {
@@ -2161,7 +2159,7 @@
     return Return::Ok();
 }
 
-SnapshotManager::Return SnapshotManager::InitializeUpdateSnapshots(
+Return SnapshotManager::InitializeUpdateSnapshots(
         LockedFile* lock, MetadataBuilder* target_metadata,
         const LpMetadata* exported_target_metadata, const std::string& target_suffix,
         const std::map<std::string, SnapshotStatus>& all_snapshot_status) {
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index cea9d69..47ac474 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -1604,7 +1604,7 @@
     ASSERT_TRUE(sm->BeginUpdate());
     auto res = sm->CreateUpdateSnapshots(manifest_);
     ASSERT_FALSE(res);
-    ASSERT_EQ(SnapshotManager::Return::ErrorCode::NO_SPACE, res.error_code());
+    ASSERT_EQ(Return::ErrorCode::NO_SPACE, res.error_code());
     ASSERT_GE(res.required_size(), 14_MiB);
     ASSERT_LT(res.required_size(), 15_MiB);
 }
diff --git a/fs_mgr/libsnapshot/utility.cpp b/fs_mgr/libsnapshot/utility.cpp
index f01500f..3a64448 100644
--- a/fs_mgr/libsnapshot/utility.cpp
+++ b/fs_mgr/libsnapshot/utility.cpp
@@ -86,9 +86,7 @@
     }
 }
 
-SnapshotManager::Return InitializeCow(const std::string& device) {
-    using Return = SnapshotManager::Return;
-
+Return InitializeCow(const std::string& device) {
     // When the kernel creates a persistent dm-snapshot, it requires a CoW file
     // to store the modifications. The kernel interface does not specify how
     // the CoW is used, and there is no standard associated.
diff --git a/fs_mgr/libsnapshot/utility.h b/fs_mgr/libsnapshot/utility.h
index 0453256..ad46090 100644
--- a/fs_mgr/libsnapshot/utility.h
+++ b/fs_mgr/libsnapshot/utility.h
@@ -111,7 +111,7 @@
         android::fs_mgr::MetadataBuilder* builder, const std::string& suffix);
 
 // Initialize a device before using it as the COW device for a dm-snapshot device.
-SnapshotManager::Return InitializeCow(const std::string& device);
+Return InitializeCow(const std::string& device);
 
 // "Atomically" write string to file. This is done by a series of actions:
 // 1. Write to path + ".tmp"
diff --git a/fs_mgr/libvbmeta/Android.bp b/fs_mgr/libvbmeta/Android.bp
index 937e0f3..bceabab 100644
--- a/fs_mgr/libvbmeta/Android.bp
+++ b/fs_mgr/libvbmeta/Android.bp
@@ -37,6 +37,7 @@
 cc_test_host {
     name: "libvbmeta_test",
     static_libs: [
+        "liblog",
         "libsparse",
         "libvbmeta",
         "libz",
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 2a6df84..c877590 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -1119,19 +1119,28 @@
 }
 
 static Result<void> ExecVdcRebootOnFailure(const std::string& vdc_arg) {
+    bool should_reboot_into_recovery = true;
     auto reboot_reason = vdc_arg + "_failed";
+    if (android::sysprop::InitProperties::userspace_reboot_in_progress().value_or(false)) {
+        should_reboot_into_recovery = false;
+    }
 
-    auto reboot = [reboot_reason](const std::string& message) {
+    auto reboot = [reboot_reason, should_reboot_into_recovery](const std::string& message) {
         // TODO (b/122850122): support this in gsi
-        if (fscrypt_is_native() && !android::gsi::IsGsiRunning()) {
-            LOG(ERROR) << message << ": Rebooting into recovery, reason: " << reboot_reason;
-            if (auto result = reboot_into_recovery(
-                        {"--prompt_and_wipe_data", "--reason="s + reboot_reason});
-                !result) {
-                LOG(FATAL) << "Could not reboot into recovery: " << result.error();
+        if (should_reboot_into_recovery) {
+            if (fscrypt_is_native() && !android::gsi::IsGsiRunning()) {
+                LOG(ERROR) << message << ": Rebooting into recovery, reason: " << reboot_reason;
+                if (auto result = reboot_into_recovery(
+                            {"--prompt_and_wipe_data", "--reason="s + reboot_reason});
+                    !result) {
+                    LOG(FATAL) << "Could not reboot into recovery: " << result.error();
+                }
+            } else {
+                LOG(ERROR) << "Failure (reboot suppressed): " << reboot_reason;
             }
         } else {
-            LOG(ERROR) << "Failure (reboot suppressed): " << reboot_reason;
+            LOG(ERROR) << message << ": rebooting, reason: " << reboot_reason;
+            trigger_shutdown("reboot," + reboot_reason);
         }
     };
 
@@ -1267,7 +1276,7 @@
         if (strchr(name, '@') != nullptr) continue;
 
         auto path = "/data/misc/apexdata/" + std::string(name);
-        auto options = MkdirOptions{path, 0770, AID_ROOT, AID_SYSTEM, FscryptAction::kNone, "ref"};
+        auto options = MkdirOptions{path, 0771, AID_ROOT, AID_SYSTEM, FscryptAction::kNone, "ref"};
         make_dir_with_options(options);
     }
     return {};
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 6d1259d..9da32e4 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -58,7 +58,6 @@
 using android::fs_mgr::ReadFstabFromDt;
 using android::fs_mgr::SkipMountingPartitions;
 using android::fs_mgr::TransformFstabForDsu;
-using android::init::WriteFile;
 using android::snapshot::SnapshotManager;
 
 using namespace std::literals;
@@ -620,7 +619,13 @@
         }
         return InitRequiredDevices(std::move(devices));
     };
-    auto images = IImageManager::Open("dsu", 0ms);
+    std::string active_dsu;
+    if (!gsi::GetActiveDsu(&active_dsu)) {
+        LOG(ERROR) << "Failed to GetActiveDsu";
+        return;
+    }
+    LOG(INFO) << "DSU slot: " << active_dsu;
+    auto images = IImageManager::Open("dsu/" + active_dsu, 0ms);
     if (!images || !images->MapAllImages(init_devices)) {
         LOG(ERROR) << "DSU partition layout could not be instantiated";
         return;
diff --git a/init/init.cpp b/init/init.cpp
index 5f97e44..a25bf6c 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -730,8 +730,8 @@
     }
 
     am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
-
     am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
+    am.QueueBuiltinAction(TestPerfEventSelinuxAction, "TestPerfEventSelinux");
     am.QueueEventTrigger("early-init");
 
     // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index b811622..1a474fb 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -107,7 +107,7 @@
 }
 
 static Result<void> MountDir(const std::string& path, const std::string& mount_path) {
-    if (int ret = mkdir(mount_path.c_str(), 0755); ret != 0 && ret != EEXIST) {
+    if (int ret = mkdir(mount_path.c_str(), 0755); ret != 0 && errno != EEXIST) {
         return ErrnoError() << "Could not create mount point " << mount_path;
     }
     if (mount(path.c_str(), mount_path.c_str(), nullptr, MS_BIND, nullptr) != 0) {
diff --git a/init/security.cpp b/init/security.cpp
index 586d0c7..6cbe642 100644
--- a/init/security.cpp
+++ b/init/security.cpp
@@ -18,14 +18,19 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <linux/perf_event.h>
+#include <sys/ioctl.h>
+#include <sys/syscall.h>
 #include <unistd.h>
 
 #include <fstream>
 
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android-base/unique_fd.h>
 
 using android::base::unique_fd;
+using android::base::SetProperty;
 
 namespace android {
 namespace init {
@@ -197,5 +202,61 @@
     return {};
 }
 
+// Test for whether the kernel has SELinux hooks for the perf_event_open()
+// syscall. If the hooks are present, we can stop using the other permission
+// mechanism (perf_event_paranoid sysctl), and use only the SELinux policy to
+// control access to the syscall. The hooks are expected on all Android R
+// release kernels, but might be absent on devices that upgrade while keeping an
+// older kernel.
+//
+// There is no direct/synchronous way of finding out that a syscall failed due
+// to SELinux. Therefore we test for a combination of a success and a failure
+// that are explained by the platform's SELinux policy for the "init" domain:
+// * cpu-scoped perf_event is allowed
+// * ioctl() on the event fd is disallowed with EACCES
+//
+// Since init has CAP_SYS_ADMIN, these tests are not affected by the system-wide
+// perf_event_paranoid sysctl.
+//
+// If the SELinux hooks are detected, a special sysprop
+// (sys.init.perf_lsm_hooks) is set, which translates to a modification of
+// perf_event_paranoid (through init.rc sysprop actions).
+//
+// TODO(b/137092007): this entire test can be removed once the platform stops
+// supporting kernels that precede the perf_event_open hooks (Android common
+// kernels 4.4 and 4.9).
+Result<void> TestPerfEventSelinuxAction(const BuiltinArguments&) {
+    // Use a trivial event that will be configured, but not started.
+    struct perf_event_attr pe = {
+            .type = PERF_TYPE_SOFTWARE,
+            .size = sizeof(struct perf_event_attr),
+            .config = PERF_COUNT_SW_TASK_CLOCK,
+            .disabled = 1,
+            .exclude_kernel = 1,
+    };
+
+    // Open the above event targeting cpu 0. (EINTR not possible.)
+    unique_fd fd(static_cast<int>(syscall(__NR_perf_event_open, &pe, /*pid=*/-1,
+                                          /*cpu=*/0,
+                                          /*group_fd=*/-1, /*flags=*/0)));
+    if (fd == -1) {
+        PLOG(ERROR) << "Unexpected perf_event_open error";
+        return {};
+    }
+
+    int ioctl_ret = ioctl(fd, PERF_EVENT_IOC_RESET);
+    if (ioctl_ret != -1) {
+        // Success implies that the kernel doesn't have the hooks.
+        return {};
+    } else if (errno != EACCES) {
+        PLOG(ERROR) << "Unexpected perf_event ioctl error";
+        return {};
+    }
+
+    // Conclude that the SELinux hooks are present.
+    SetProperty("sys.init.perf_lsm_hooks", "1");
+    return {};
+}
+
 }  // namespace init
 }  // namespace android
diff --git a/init/security.h b/init/security.h
index b081a05..43c2739 100644
--- a/init/security.h
+++ b/init/security.h
@@ -29,6 +29,7 @@
 Result<void> MixHwrngIntoLinuxRngAction(const BuiltinArguments&);
 Result<void> SetMmapRndBitsAction(const BuiltinArguments&);
 Result<void> SetKptrRestrictAction(const BuiltinArguments&);
+Result<void> TestPerfEventSelinuxAction(const BuiltinArguments&);
 
 }  // namespace init
 }  // namespace android
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 334364e..65af2b3 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -250,9 +250,8 @@
     require_root: true,
 }
 
-cc_test {
-    name: "libcutils_test_static",
-    test_suites: ["device-tests"],
+cc_defaults {
+    name: "libcutils_test_static_defaults",
     defaults: ["libcutils_test_default"],
     static_libs: [
         "libc",
@@ -272,3 +271,16 @@
         },
     },
 }
+
+cc_test {
+    name: "libcutils_test_static",
+    test_suites: ["device-tests"],
+    defaults: ["libcutils_test_static_defaults"],
+}
+
+cc_test {
+    name: "KernelLibcutilsTest",
+    test_suites: ["general-tests", "vts-core"],
+    defaults: ["libcutils_test_static_defaults"],
+    test_config: "KernelLibcutilsTest.xml",
+}
diff --git a/libcutils/KernelLibcutilsTest.xml b/libcutils/KernelLibcutilsTest.xml
new file mode 100644
index 0000000..e27fac6
--- /dev/null
+++ b/libcutils/KernelLibcutilsTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<configuration description="Runs libcutils_test_static.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="libcutils_test_static->/data/local/tmp/libcutils_test_static" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="libcutils_test_static" />
+        <option name="include-filter" value="*AshmemTest*" />
+    </test>
+</configuration>
diff --git a/libcutils/ashmem-dev.cpp b/libcutils/ashmem-dev.cpp
index 340572c..8c232f0 100644
--- a/libcutils/ashmem-dev.cpp
+++ b/libcutils/ashmem-dev.cpp
@@ -203,19 +203,23 @@
 {
     static const std::string ashmem_device_path = get_ashmem_device_path();
 
-    int ret;
-    struct stat st;
-
     if (ashmem_device_path.empty()) {
         return -1;
     }
 
     int fd = TEMP_FAILURE_RETRY(open(ashmem_device_path.c_str(), O_RDWR | O_CLOEXEC));
+
+    // fallback for APEX w/ use_vendor on Q, which would have still used /dev/ashmem
+    if (fd < 0) {
+        fd = TEMP_FAILURE_RETRY(open("/dev/ashmem", O_RDWR | O_CLOEXEC));
+    }
+
     if (fd < 0) {
         return fd;
     }
 
-    ret = TEMP_FAILURE_RETRY(fstat(fd, &st));
+    struct stat st;
+    int ret = TEMP_FAILURE_RETRY(fstat(fd, &st));
     if (ret < 0) {
         int save_errno = errno;
         close(fd);
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index e1e8230..f9a3df9 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -129,6 +129,7 @@
 #define AID_NETWORK_STACK 1073   /* network stack service */
 #define AID_GSID 1074            /* GSI service daemon */
 #define AID_FSVERITY_CERT 1075   /* fs-verity key ownership in keystore */
+#define AID_CREDSTORE 1076       /* identity credential manager service */
 /* Changes to this file must be made in AOSP, *not* in internal branches. */
 
 #define AID_SHELL 2000 /* adb and debug shell user */
diff --git a/liblog/Android.bp b/liblog/Android.bp
index bab57c0..58c96b6 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -103,7 +103,7 @@
 
     stubs: {
         symbol_file: "liblog.map.txt",
-        versions: ["10000"],
+        versions: ["29", "30"],
     },
 
     // TODO(tomcherry): Renable this before release branch is cut
diff --git a/liblog/fake_log_device.cpp b/liblog/fake_log_device.cpp
index 2582cea..f1147dc 100644
--- a/liblog/fake_log_device.cpp
+++ b/liblog/fake_log_device.cpp
@@ -517,13 +517,16 @@
 }
 
 int __android_log_is_loggable(int prio, const char*, int def) {
-  int logLevel = def;
-  return logLevel >= 0 && prio >= logLevel;
+  int minimum_priority = __android_log_get_minimum_priority();
+  if (minimum_priority == ANDROID_LOG_DEFAULT) {
+    return prio >= def;
+  } else {
+    return prio >= minimum_priority;
+  }
 }
 
 int __android_log_is_loggable_len(int prio, const char*, size_t, int def) {
-  int logLevel = def;
-  return logLevel >= 0 && prio >= logLevel;
+  return __android_log_is_loggable(prio, nullptr, def);
 }
 
 int __android_log_is_debuggable() {
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
index 7290789..6530704 100644
--- a/liblog/include/android/log.h
+++ b/liblog/include/android/log.h
@@ -55,6 +55,7 @@
  */
 
 #include <stdarg.h>
+#include <stddef.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -152,6 +153,12 @@
 } log_id_t;
 
 /**
+ * Let the logging function choose the best log target.
+ * This is not part of the enum since adding either -1 or 0xFFFFFFFF forces the enum to be signed or
+ * unsigned, which breaks unfortunately common arithmetic against LOG_ID_MIN and LOG_ID_MAX. */
+#define LOG_ID_DEFAULT -1
+
+/**
  * Writes the constant string `text` to the log buffer `id`,
  * with priority `prio` and tag `tag`.
  *
@@ -170,6 +177,101 @@
 int __android_log_buf_print(int bufID, int prio, const char* tag, const char* fmt, ...)
     __attribute__((__format__(printf, 4, 5)));
 
+/**
+ * Logger data struct used for writing log messages to liblog via __android_log_write_logger_data()
+ * and sending log messages to user defined loggers specified in __android_log_set_logger().
+ */
+struct __android_logger_data {
+  size_t struct_size; /* Must be set to sizeof(__android_logger_data) and is used for versioning. */
+  int buffer_id;      /* log_id_t or -1 to represent 'default'. */
+  int priority;       /* android_LogPriority values. */
+  const char* tag;
+  const char* file;  /* Optional file name, may be set to nullptr. */
+  unsigned int line; /* Optional line number, ignore if file is nullptr. */
+};
+
+/**
+ * Writes the log message specified with logger_data and msg to the log.  logger_data includes
+ * additional file name and line number information that a logger may use.  logger_data is versioned
+ * for backwards compatibility.
+ */
+void __android_log_write_logger_data(struct __android_logger_data* logger_data, const char* msg);
+
+/**
+ * Prototype for the 'logger' function that is called for every log message.
+ */
+typedef void (*__android_logger_function)(const struct __android_logger_data* logger_data,
+                                          const char* message);
+
+/**
+ * Sets a user defined logger function.  All log messages sent to liblog will be set to the
+ * function pointer specified by logger for processing.
+ */
+void __android_log_set_logger(__android_logger_function logger);
+
+/**
+ * Writes the log message to logd.  This is an __android_logger_function and can be provided to
+ * __android_log_set_logger().  It is the default logger when running liblog on a device.
+ */
+void __android_log_logd_logger(const struct __android_logger_data* logger_data, const char* msg);
+
+/**
+ * Writes the log message to stderr.  This is an __android_logger_function and can be provided to
+ * __android_log_set_logger().  It is the default logger when running liblog on host.
+ */
+void __android_log_stderr_logger(const struct __android_logger_data* logger_data,
+                                 const char* message);
+
+/**
+ * Prototype for the 'abort' function that is called when liblog will abort due to
+ * __android_log_assert() failures.
+ */
+typedef void (*__android_aborter_function)(const char* abort_message);
+
+/**
+ * Sets a user defined aborter function that is called for __android_log_assert() failures.
+ */
+void __android_log_set_aborter(__android_aborter_function aborter);
+
+/**
+ * Calls the stored aborter function.  This allows for other logging libraries to use the same
+ * aborter function by calling this function in liblog.
+ */
+void __android_log_call_aborter(const char* abort_message);
+
+/**
+ * Sets android_set_abort_message() on device then aborts().  This is the default aborter.
+ */
+void __android_log_default_aborter(const char* abort_message);
+
+/**
+ * Use the per-tag properties "log.tag.<tagname>" along with the minimum priority from
+ * __android_log_set_minimum_priority() to determine if a log message with a given prio and tag will
+ * be printed.  A non-zero result indicates yes, zero indicates false.
+ *
+ * If both a priority for a tag and a minimum priority are set by
+ * __android_log_set_minimum_priority(), then the lowest of the two values are to determine the
+ * minimum priority needed to log.  If only one is set, then that value is used to determine the
+ * minimum priority needed.  If none are set, then default_priority is used.
+ *
+ * prio is ANDROID_LOG_VERBOSE to ANDROID_LOG_FATAL.
+ */
+int __android_log_is_loggable(int prio, const char* tag, int default_prio);
+int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio);
+
+/**
+ * Sets the minimum priority that will be logged for this process.
+ *
+ * This returns the previous set minimum priority, or ANDROID_LOG_DEFAULT if none was set.
+ */
+int __android_log_set_minimum_priority(int priority);
+
+/**
+ * Gets the minimum priority that will be logged for this process.  If none has been set by a
+ * previous __android_log_set_minimum_priority() call, this returns ANDROID_LOG_DEFAULT.
+ */
+int __android_log_get_minimum_priority();
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/liblog/liblog.map.txt b/liblog/liblog.map.txt
index 2dd8059..62b9805 100644
--- a/liblog/liblog.map.txt
+++ b/liblog/liblog.map.txt
@@ -54,18 +54,31 @@
     __android_log_is_debuggable; # apex llndk
 };
 
-LIBLOG_Q {
+LIBLOG_Q { # introduced=29
   global:
     __android_log_bswrite; # apex
     __android_log_btwrite; # apex
     __android_log_bwrite; # apex
     __android_log_close; # apex
     __android_log_security; # apex
-    __android_log_security_bswrite; # apex
     android_log_reset; # llndk
     android_log_parser_reset; # llndk
 };
 
+LIGLOG_R { # introduced=30
+  global:
+    __android_log_call_aborter;
+    __android_log_default_aborter;
+    __android_log_get_minimum_priority;
+    __android_log_logd_logger;
+    __android_log_security_bswrite; # apex
+    __android_log_set_aborter;
+    __android_log_set_logger;
+    __android_log_set_minimum_priority;
+    __android_log_stderr_logger;
+    __android_log_write_logger_data;
+};
+
 LIBLOG_PRIVATE {
   global:
     __android_log_pmsg_file_read;
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index d6ef951..61b6fce 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <errno.h>
+#include <inttypes.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/time.h>
@@ -23,11 +24,15 @@
 #include <android/set_abort_message.h>
 #endif
 
+#include <shared_mutex>
+
 #include <android-base/macros.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
+#include "android/log.h"
 #include "logger.h"
+#include "rwlock.h"
 #include "uio.h"
 
 #if (FAKE_LOG_DEVICE == 0)
@@ -37,6 +42,14 @@
 #include "fake_log_device.h"
 #endif
 
+#if defined(__APPLE__)
+#include <pthread.h>
+#elif defined(__linux__) && !defined(__ANDROID__)
+#include <syscall.h>
+#elif defined(_WIN32)
+#include <windows.h>
+#endif
+
 #define LOG_BUF_SIZE 1024
 
 #if defined(__ANDROID__)
@@ -93,6 +106,52 @@
 #endif
 }
 
+static int minimum_log_priority = ANDROID_LOG_DEFAULT;
+int __android_log_set_minimum_priority(int priority) {
+  int old_minimum_log_priority = minimum_log_priority;
+  minimum_log_priority = priority;
+  return old_minimum_log_priority;
+}
+
+int __android_log_get_minimum_priority() {
+  return minimum_log_priority;
+}
+
+#ifdef __ANDROID__
+static __android_logger_function logger_function = __android_log_logd_logger;
+#else
+static __android_logger_function logger_function = __android_log_stderr_logger;
+#endif
+static RwLock logger_function_lock;
+
+void __android_log_set_logger(__android_logger_function logger) {
+  auto lock = std::unique_lock{logger_function_lock};
+  logger_function = logger;
+}
+
+void __android_log_default_aborter(const char* abort_message) {
+#ifdef __ANDROID__
+  android_set_abort_message(abort_message);
+#else
+  UNUSED(abort_message);
+#endif
+  abort();
+}
+
+static __android_aborter_function aborter_function = __android_log_default_aborter;
+static RwLock aborter_function_lock;
+
+void __android_log_set_aborter(__android_aborter_function aborter) {
+  auto lock = std::unique_lock{aborter_function_lock};
+  aborter_function = aborter;
+}
+
+void __android_log_call_aborter(const char* abort_message) {
+  auto lock = std::shared_lock{aborter_function_lock};
+  aborter_function(abort_message);
+}
+
+#ifdef __ANDROID__
 static int write_to_log(log_id_t log_id, struct iovec* vec, size_t nr) {
   int ret, save_errno;
   struct timespec ts;
@@ -103,7 +162,6 @@
     return -EINVAL;
   }
 
-#if defined(__ANDROID__)
   clock_gettime(android_log_clockid(), &ts);
 
   if (log_id == LOG_ID_SECURITY) {
@@ -137,51 +195,106 @@
       return -EPERM;
     }
   }
-#else
-  /* simulate clock_gettime(CLOCK_REALTIME, &ts); */
-  {
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    ts.tv_sec = tv.tv_sec;
-    ts.tv_nsec = tv.tv_usec * 1000;
-  }
-#endif
 
-  ret = 0;
-
-#if (FAKE_LOG_DEVICE == 0)
   ret = LogdWrite(log_id, &ts, vec, nr);
   PmsgWrite(log_id, &ts, vec, nr);
-#else
-  ret = FakeWrite(log_id, &ts, vec, nr);
-#endif
 
   errno = save_errno;
   return ret;
 }
+#else
+static int write_to_log(log_id_t, struct iovec*, size_t) {
+  // Non-Android text logs should go to __android_log_stderr_logger, not here.
+  // Non-Android binary logs are always dropped.
+  return 1;
+}
+#endif
+
+// Copied from base/threads.cpp
+static uint64_t GetThreadId() {
+#if defined(__BIONIC__)
+  return gettid();
+#elif defined(__APPLE__)
+  uint64_t tid;
+  pthread_threadid_np(NULL, &tid);
+  return tid;
+#elif defined(__linux__)
+  return syscall(__NR_gettid);
+#elif defined(_WIN32)
+  return GetCurrentThreadId();
+#endif
+}
+
+void __android_log_stderr_logger(const struct __android_logger_data* logger_data,
+                                 const char* message) {
+  struct tm now;
+  time_t t = time(nullptr);
+
+#if defined(_WIN32)
+  localtime_s(&now, &t);
+#else
+  localtime_r(&t, &now);
+#endif
+
+  char timestamp[32];
+  strftime(timestamp, sizeof(timestamp), "%m-%d %H:%M:%S", &now);
+
+  static const char log_characters[] = "XXVDIWEF";
+  static_assert(arraysize(log_characters) - 1 == ANDROID_LOG_SILENT,
+                "Mismatch in size of log_characters and values in android_LogPriority");
+  int priority =
+      logger_data->priority > ANDROID_LOG_SILENT ? ANDROID_LOG_FATAL : logger_data->priority;
+  char priority_char = log_characters[priority];
+  uint64_t tid = GetThreadId();
+
+  if (logger_data->file != nullptr) {
+    fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s:%u] %s\n",
+            logger_data->tag ? logger_data->tag : "nullptr", priority_char, timestamp, getpid(),
+            tid, logger_data->file, logger_data->line, message);
+  } else {
+    fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s\n",
+            logger_data->tag ? logger_data->tag : "nullptr", priority_char, timestamp, getpid(),
+            tid, message);
+  }
+}
+
+void __android_log_logd_logger(const struct __android_logger_data* logger_data,
+                               const char* message) {
+  int buffer_id = logger_data->buffer_id == LOG_ID_DEFAULT ? LOG_ID_MAIN : logger_data->buffer_id;
+
+  struct iovec vec[3];
+  vec[0].iov_base =
+      const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(&logger_data->priority));
+  vec[0].iov_len = 1;
+  vec[1].iov_base = const_cast<void*>(static_cast<const void*>(logger_data->tag));
+  vec[1].iov_len = strlen(logger_data->tag) + 1;
+  vec[2].iov_base = const_cast<void*>(static_cast<const void*>(message));
+  vec[2].iov_len = strlen(message) + 1;
+
+  write_to_log(static_cast<log_id_t>(buffer_id), vec, 3);
+}
 
 int __android_log_write(int prio, const char* tag, const char* msg) {
   return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
 }
 
-int __android_log_buf_write(int bufID, int prio, const char* tag, const char* msg) {
-  if (!tag) tag = "";
+void __android_log_write_logger_data(__android_logger_data* logger_data, const char* msg) {
+  if (logger_data->tag == nullptr) logger_data->tag = "";
 
 #if __BIONIC__
-  if (prio == ANDROID_LOG_FATAL) {
+  if (logger_data->priority == ANDROID_LOG_FATAL) {
     android_set_abort_message(msg);
   }
 #endif
 
-  struct iovec vec[3];
-  vec[0].iov_base = (unsigned char*)&prio;
-  vec[0].iov_len = 1;
-  vec[1].iov_base = (void*)tag;
-  vec[1].iov_len = strlen(tag) + 1;
-  vec[2].iov_base = (void*)msg;
-  vec[2].iov_len = strlen(msg) + 1;
+  auto lock = std::shared_lock{logger_function_lock};
+  logger_function(logger_data, msg);
+}
 
-  return write_to_log(static_cast<log_id_t>(bufID), vec, 3);
+int __android_log_buf_write(int bufID, int prio, const char* tag, const char* msg) {
+  __android_logger_data logger_data = {sizeof(__android_logger_data), bufID, prio, tag, nullptr, 0};
+  __android_log_write_logger_data(&logger_data, msg);
+  return 1;
 }
 
 int __android_log_vprint(int prio, const char* tag, const char* fmt, va_list ap) {
@@ -239,8 +352,8 @@
   TEMP_FAILURE_RETRY(write(2, "\n", 1));
 
   __android_log_write(ANDROID_LOG_FATAL, tag, buf);
-  abort(); /* abort so we have a chance to debug the situation */
-           /* NOTREACHED */
+  __android_log_call_aborter(buf);
+  abort();
 }
 
 int __android_log_bwrite(int32_t tag, const void* payload, size_t len) {
diff --git a/liblog/properties.cpp b/liblog/properties.cpp
index 2b2327c..a53c92b 100644
--- a/liblog/properties.cpp
+++ b/liblog/properties.cpp
@@ -24,6 +24,8 @@
 #include <sys/_system_properties.h>
 #include <unistd.h>
 
+#include <algorithm>
+
 #include <private/android_logger.h>
 
 static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER;
@@ -87,7 +89,7 @@
   }
 }
 
-static int __android_log_level(const char* tag, size_t len, int default_prio) {
+static int __android_log_level(const char* tag, size_t len) {
   /* sizeof() is used on this array below */
   static const char log_namespace[] = "persist.log.tag.";
   static const size_t base_offset = 8; /* skip "persist." */
@@ -256,20 +258,30 @@
     case 'F': /* FALLTHRU */ /* Not officially supported */
     case 'A': return ANDROID_LOG_FATAL;
     case BOOLEAN_FALSE: /* FALLTHRU */ /* Not Officially supported */
-    case 'S': return -1; /* ANDROID_LOG_SUPPRESS */
+    case 'S': return ANDROID_LOG_SILENT;
       /* clang-format on */
   }
-  return default_prio;
+  return -1;
 }
 
 int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio) {
-  int logLevel = __android_log_level(tag, len, default_prio);
-  return logLevel >= 0 && prio >= logLevel;
+  int minimum_log_priority = __android_log_get_minimum_priority();
+  int property_log_level = __android_log_level(tag, len);
+
+  if (property_log_level >= 0 && minimum_log_priority != ANDROID_LOG_DEFAULT) {
+    return prio >= std::min(property_log_level, minimum_log_priority);
+  } else if (property_log_level >= 0) {
+    return prio >= property_log_level;
+  } else if (minimum_log_priority != ANDROID_LOG_DEFAULT) {
+    return prio >= minimum_log_priority;
+  } else {
+    return prio >= default_prio;
+  }
 }
 
 int __android_log_is_loggable(int prio, const char* tag, int default_prio) {
-  int logLevel = __android_log_level(tag, (tag && *tag) ? strlen(tag) : 0, default_prio);
-  return logLevel >= 0 && prio >= logLevel;
+  auto len = tag ? strlen(tag) : 0;
+  return __android_log_is_loggable_len(prio, tag, len, default_prio);
 }
 
 int __android_log_is_debuggable() {
diff --git a/liblog/tests/Android.bp b/liblog/tests/Android.bp
index f58c524..3288954 100644
--- a/liblog/tests/Android.bp
+++ b/liblog/tests/Android.bp
@@ -54,6 +54,7 @@
     ],
     srcs: [
         "libc_test.cpp",
+        "liblog_global_state.cpp",
         "liblog_test.cpp",
         "log_id_test.cpp",
         "log_radio_test.cpp",
diff --git a/liblog/tests/liblog_global_state.cpp b/liblog/tests/liblog_global_state.cpp
new file mode 100644
index 0000000..8d73bb8
--- /dev/null
+++ b/liblog/tests/liblog_global_state.cpp
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2020 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 "global_state_test_tag"
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/log.h>
+
+#include <gtest/gtest.h>
+
+TEST(liblog_global_state, libbase_logs_with_libbase_SetLogger) {
+  using namespace android::base;
+  bool message_seen = false;
+  LogSeverity expected_severity = WARNING;
+  std::string expected_file = Basename(__FILE__);
+  unsigned int expected_line;
+  std::string expected_message = "libbase test message";
+
+  auto LoggerFunction = [&](LogId log_id, LogSeverity severity, const char* tag, const char* file,
+                            unsigned int line, const char* message) {
+    message_seen = true;
+    EXPECT_EQ(DEFAULT, log_id);
+    EXPECT_EQ(expected_severity, severity);
+    EXPECT_STREQ(LOG_TAG, tag);
+    EXPECT_EQ(expected_file, file);
+    EXPECT_EQ(expected_line, line);
+    EXPECT_EQ(expected_message, message);
+  };
+
+  SetLogger(LoggerFunction);
+
+  expected_line = __LINE__ + 1;
+  LOG(expected_severity) << expected_message;
+  EXPECT_TRUE(message_seen);
+}
+
+TEST(liblog_global_state, libbase_logs_with_liblog_set_logger) {
+  using namespace android::base;
+  // These must be static since they're used by the liblog logger function, which only accepts
+  // lambdas without captures.  The items used by the libbase logger are explicitly not static, to
+  // ensure that lambdas with captures do work there.
+  static bool message_seen = false;
+  static std::string expected_file = Basename(__FILE__);
+  static unsigned int expected_line;
+  static std::string expected_message = "libbase test message";
+
+  auto liblog_logger_function = [](const struct __android_logger_data* logger_data,
+                                   const char* message) {
+    message_seen = true;
+    EXPECT_EQ(sizeof(__android_logger_data), logger_data->struct_size);
+    EXPECT_EQ(LOG_ID_DEFAULT, logger_data->buffer_id);
+    EXPECT_EQ(ANDROID_LOG_WARN, logger_data->priority);
+    EXPECT_STREQ(LOG_TAG, logger_data->tag);
+    EXPECT_EQ(expected_file, logger_data->file);
+    EXPECT_EQ(expected_line, logger_data->line);
+    EXPECT_EQ(expected_message, message);
+  };
+
+  __android_log_set_logger(liblog_logger_function);
+
+  expected_line = __LINE__ + 1;
+  LOG(WARNING) << expected_message;
+  EXPECT_TRUE(message_seen);
+}
+
+TEST(liblog_global_state, liblog_logs_with_libbase_SetLogger) {
+  using namespace android::base;
+  bool message_seen = false;
+  std::string expected_message = "libbase test message";
+
+  auto LoggerFunction = [&](LogId log_id, LogSeverity severity, const char* tag, const char* file,
+                            unsigned int line, const char* message) {
+    message_seen = true;
+    EXPECT_EQ(MAIN, log_id);
+    EXPECT_EQ(WARNING, severity);
+    EXPECT_STREQ(LOG_TAG, tag);
+    EXPECT_EQ(nullptr, file);
+    EXPECT_EQ(0U, line);
+    EXPECT_EQ(expected_message, message);
+  };
+
+  SetLogger(LoggerFunction);
+
+  __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_WARN, LOG_TAG, expected_message.c_str());
+  EXPECT_TRUE(message_seen);
+  message_seen = false;
+}
+
+TEST(liblog_global_state, liblog_logs_with_liblog_set_logger) {
+  using namespace android::base;
+  // These must be static since they're used by the liblog logger function, which only accepts
+  // lambdas without captures.  The items used by the libbase logger are explicitly not static, to
+  // ensure that lambdas with captures do work there.
+  static bool message_seen = false;
+  static int expected_buffer_id = LOG_ID_MAIN;
+  static int expected_priority = ANDROID_LOG_WARN;
+  static std::string expected_message = "libbase test message";
+
+  auto liblog_logger_function = [](const struct __android_logger_data* logger_data,
+                                   const char* message) {
+    message_seen = true;
+    EXPECT_EQ(sizeof(__android_logger_data), logger_data->struct_size);
+    EXPECT_EQ(expected_buffer_id, logger_data->buffer_id);
+    EXPECT_EQ(expected_priority, logger_data->priority);
+    EXPECT_STREQ(LOG_TAG, logger_data->tag);
+    EXPECT_STREQ(nullptr, logger_data->file);
+    EXPECT_EQ(0U, logger_data->line);
+    EXPECT_EQ(expected_message, message);
+  };
+
+  __android_log_set_logger(liblog_logger_function);
+
+  __android_log_buf_write(expected_buffer_id, expected_priority, LOG_TAG, expected_message.c_str());
+  EXPECT_TRUE(message_seen);
+}
+
+TEST(liblog_global_state, SetAborter_with_liblog) {
+  using namespace android::base;
+
+  std::string expected_message = "libbase test message";
+  static bool message_seen = false;
+  auto aborter_function = [&](const char* message) {
+    message_seen = true;
+    EXPECT_EQ(expected_message, message);
+  };
+
+  SetAborter(aborter_function);
+  LOG(FATAL) << expected_message;
+  EXPECT_TRUE(message_seen);
+  message_seen = false;
+
+  static std::string expected_message_static = "libbase test message";
+  auto liblog_aborter_function = [](const char* message) {
+    message_seen = true;
+    EXPECT_EQ(expected_message_static, message);
+  };
+  __android_log_set_aborter(liblog_aborter_function);
+  LOG(FATAL) << expected_message_static;
+  EXPECT_TRUE(message_seen);
+  message_seen = false;
+}
+
+TEST(liblog_global_state, is_loggable_both_default) {
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+}
+
+TEST(liblog_global_state, is_loggable_minimum_log_priority_only) {
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  EXPECT_EQ(ANDROID_LOG_DEFAULT, __android_log_set_minimum_priority(ANDROID_LOG_DEBUG));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  EXPECT_EQ(ANDROID_LOG_DEBUG, __android_log_set_minimum_priority(ANDROID_LOG_WARN));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  EXPECT_EQ(android::base::WARNING, android::base::SetMinimumLogSeverity(android::base::DEBUG));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  EXPECT_EQ(android::base::DEBUG, android::base::SetMinimumLogSeverity(android::base::WARNING));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+}
+
+TEST(liblog_global_state, is_loggable_tag_log_priority_only) {
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  auto log_tag_property = std::string("log.tag.") + LOG_TAG;
+  android::base::SetProperty(log_tag_property, "d");
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  android::base::SetProperty(log_tag_property, "w");
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  android::base::SetProperty(log_tag_property, "");
+}
+
+TEST(liblog_global_state, is_loggable_both_set) {
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  // When both a tag and a minimum priority are set, we use the lower value of the two.
+
+  // tag = warning, minimum_priority = debug, expect 'debug'
+  auto log_tag_property = std::string("log.tag.") + LOG_TAG;
+  android::base::SetProperty(log_tag_property, "w");
+  EXPECT_EQ(ANDROID_LOG_DEFAULT, __android_log_set_minimum_priority(ANDROID_LOG_DEBUG));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  // tag = warning, minimum_priority = warning, expect 'warning'
+  EXPECT_EQ(ANDROID_LOG_DEBUG, __android_log_set_minimum_priority(ANDROID_LOG_WARN));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  // tag = debug, minimum_priority = warning, expect 'debug'
+  android::base::SetProperty(log_tag_property, "d");
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  // tag = debug, minimum_priority = debug, expect 'debug'
+  EXPECT_EQ(ANDROID_LOG_WARN, __android_log_set_minimum_priority(ANDROID_LOG_DEBUG));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  android::base::SetProperty(log_tag_property, "");
+}
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index c402e20..75a26bf 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -1074,7 +1074,6 @@
 
     // Once we've found our expected entry, break.
     if (len == LOGGER_ENTRY_MAX_PAYLOAD - sizeof(big_payload_tag)) {
-      EXPECT_EQ(ret, len + static_cast<ssize_t>(sizeof(big_payload_tag)));
       *found = true;
     }
   };
@@ -1259,14 +1258,10 @@
     int level;
     char type;
   } levels[] = {
-    { ANDROID_LOG_VERBOSE, 'v' },
-    { ANDROID_LOG_DEBUG, 'd' },
-    { ANDROID_LOG_INFO, 'i' },
-    { ANDROID_LOG_WARN, 'w' },
-    { ANDROID_LOG_ERROR, 'e' },
-    { ANDROID_LOG_FATAL, 'a' },
-    { -1, 's' },
-    { -2, 'g' },  // Illegal value, resort to default
+      {ANDROID_LOG_VERBOSE, 'v'}, {ANDROID_LOG_DEBUG, 'd'},
+      {ANDROID_LOG_INFO, 'i'},    {ANDROID_LOG_WARN, 'w'},
+      {ANDROID_LOG_ERROR, 'e'},   {ANDROID_LOG_FATAL, 'a'},
+      {ANDROID_LOG_SILENT, 's'},  {-2, 'g'},  // Illegal value, resort to default
   };
 
   // Set up initial test condition
diff --git a/libprocinfo/process.cpp b/libprocinfo/process.cpp
index 9194cf3..2efd49c 100644
--- a/libprocinfo/process.cpp
+++ b/libprocinfo/process.cpp
@@ -59,7 +59,6 @@
     case 'Z':
       return kProcessStateZombie;
     default:
-      LOG(ERROR) << "unknown process state: " << *state;
       return kProcessStateUnknown;
   }
 }
diff --git a/libutils/StrongPointer_test.cpp b/libutils/StrongPointer_test.cpp
index 153cf96..7b2e37f 100644
--- a/libutils/StrongPointer_test.cpp
+++ b/libutils/StrongPointer_test.cpp
@@ -56,3 +56,18 @@
     }
     ASSERT_TRUE(isDeleted) << "foo was leaked!";
 }
+
+TEST(StrongPointer, NullptrComparison) {
+    sp<SPFoo> foo;
+    ASSERT_EQ(foo, nullptr);
+    ASSERT_EQ(nullptr, foo);
+}
+
+TEST(StrongPointer, PointerComparison) {
+    bool isDeleted;
+    sp<SPFoo> foo = new SPFoo(&isDeleted);
+    ASSERT_EQ(foo.get(), foo);
+    ASSERT_EQ(foo, foo.get());
+    ASSERT_NE(nullptr, foo);
+    ASSERT_NE(foo, nullptr);
+}
diff --git a/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h
index 100e507..6f4fb47 100644
--- a/libutils/include/utils/StrongPointer.h
+++ b/libutils/include/utils/StrongPointer.h
@@ -27,43 +27,6 @@
 
 // ---------------------------------------------------------------------------
 
-// TODO: Maybe remove sp<> ? wp<> comparison? These are dangerous: If the wp<>
-// was created before the sp<>, and they point to different objects, they may
-// compare equal even if they are entirely unrelated. E.g. CameraService
-// currently performa such comparisons.
-
-#define COMPARE_STRONG(_op_)                                           \
-template<typename U>                                            \
-inline bool operator _op_ (const sp<U>& o) const {              \
-    return m_ptr _op_ o.m_ptr;                                  \
-}                                                               \
-template<typename U>                                            \
-inline bool operator _op_ (const U* o) const {                  \
-    return m_ptr _op_ o;                                        \
-}                                                               \
-/* Needed to handle type inference for nullptr: */              \
-inline bool operator _op_ (const T* o) const {                  \
-    return m_ptr _op_ o;                                        \
-}
-
-template<template<typename C> class comparator, typename T, typename U>
-static inline bool _sp_compare_(T* a, U* b) {
-    return comparator<typename std::common_type<T*, U*>::type>()(a, b);
-}
-
-// Use std::less and friends to avoid undefined behavior when ordering pointers
-// to different objects.
-#define COMPARE_STRONG_FUNCTIONAL(_op_, _compare_)               \
-template<typename U>                                             \
-inline bool operator _op_ (const sp<U>& o) const {               \
-    return _sp_compare_<_compare_>(m_ptr, o.m_ptr);              \
-}                                                                \
-template<typename U>                                             \
-inline bool operator _op_ (const U* o) const {                   \
-    return _sp_compare_<_compare_>(m_ptr, o);                    \
-}
-// ---------------------------------------------------------------------------
-
 template<typename T>
 class sp {
 public:
@@ -102,15 +65,6 @@
     inline T*       get() const            { return m_ptr; }
     inline explicit operator bool () const { return m_ptr != nullptr; }
 
-    // Operators
-
-    COMPARE_STRONG(==)
-    COMPARE_STRONG(!=)
-    COMPARE_STRONG_FUNCTIONAL(>, std::greater)
-    COMPARE_STRONG_FUNCTIONAL(<, std::less)
-    COMPARE_STRONG_FUNCTIONAL(<=, std::less_equal)
-    COMPARE_STRONG_FUNCTIONAL(>=, std::greater_equal)
-
     // Punt these to the wp<> implementation.
     template<typename U>
     inline bool operator == (const wp<U>& o) const {
@@ -130,13 +84,69 @@
     T* m_ptr;
 };
 
-// For code size reasons, we do not want these inlined or templated.
-void sp_report_race();
-void sp_report_stack_pointer();
+#define COMPARE_STRONG(_op_)                                           \
+    template <typename T, typename U>                                  \
+    static inline bool operator _op_(const sp<T>& t, const sp<U>& u) { \
+        return t.get() _op_ u.get();                                   \
+    }                                                                  \
+    template <typename T, typename U>                                  \
+    static inline bool operator _op_(const T* t, const sp<U>& u) {     \
+        return t _op_ u.get();                                         \
+    }                                                                  \
+    template <typename T, typename U>                                  \
+    static inline bool operator _op_(const sp<T>& t, const U* u) {     \
+        return t.get() _op_ u;                                         \
+    }                                                                  \
+    template <typename T>                                              \
+    static inline bool operator _op_(const sp<T>& t, std::nullptr_t) { \
+        return t.get() _op_ nullptr;                                   \
+    }                                                                  \
+    template <typename T>                                              \
+    static inline bool operator _op_(std::nullptr_t, const sp<T>& t) { \
+        return nullptr _op_ t.get();                                   \
+    }
+
+template <template <typename C> class comparator, typename T, typename U>
+static inline bool _sp_compare_(T* a, U* b) {
+    return comparator<typename std::common_type<T*, U*>::type>()(a, b);
+}
+
+#define COMPARE_STRONG_FUNCTIONAL(_op_, _compare_)                     \
+    template <typename T, typename U>                                  \
+    static inline bool operator _op_(const sp<T>& t, const sp<U>& u) { \
+        return _sp_compare_<_compare_>(t.get(), u.get());              \
+    }                                                                  \
+    template <typename T, typename U>                                  \
+    static inline bool operator _op_(const T* t, const sp<U>& u) {     \
+        return _sp_compare_<_compare_>(t, u.get());                    \
+    }                                                                  \
+    template <typename T, typename U>                                  \
+    static inline bool operator _op_(const sp<T>& t, const U* u) {     \
+        return _sp_compare_<_compare_>(t.get(), u);                    \
+    }                                                                  \
+    template <typename T>                                              \
+    static inline bool operator _op_(const sp<T>& t, std::nullptr_t) { \
+        return _sp_compare_<_compare_>(t.get(), nullptr);              \
+    }                                                                  \
+    template <typename T>                                              \
+    static inline bool operator _op_(std::nullptr_t, const sp<T>& t) { \
+        return _sp_compare_<_compare_>(nullptr, t.get());              \
+    }
+
+COMPARE_STRONG(==)
+COMPARE_STRONG(!=)
+COMPARE_STRONG_FUNCTIONAL(>, std::greater)
+COMPARE_STRONG_FUNCTIONAL(<, std::less)
+COMPARE_STRONG_FUNCTIONAL(<=, std::less_equal)
+COMPARE_STRONG_FUNCTIONAL(>=, std::greater_equal)
 
 #undef COMPARE_STRONG
 #undef COMPARE_STRONG_FUNCTIONAL
 
+// For code size reasons, we do not want these inlined or templated.
+void sp_report_race();
+void sp_report_stack_pointer();
+
 // ---------------------------------------------------------------------------
 // No user serviceable parts below here.
 
diff --git a/llkd/libllkd.cpp b/llkd/libllkd.cpp
index b26ad4d..1c3acb8 100644
--- a/llkd/libllkd.cpp
+++ b/llkd/libllkd.cpp
@@ -304,10 +304,13 @@
     bool cmdlineValid;             // cmdline has been cached
     bool updated;                  // cleared before monitoring pass.
     bool killed;                   // sent a kill to this thread, next panic...
+    bool frozen;                   // process is in frozen cgroup.
 
     void setComm(const char* _comm) { strncpy(comm + 1, _comm, sizeof(comm) - 2); }
 
-    proc(pid_t tid, pid_t pid, pid_t ppid, const char* _comm, int time, char state)
+    void setFrozen(bool _frozen) { frozen = _frozen; }
+
+    proc(pid_t tid, pid_t pid, pid_t ppid, const char* _comm, int time, char state, bool frozen)
         : tid(tid),
           schedUpdate(0),
           nrSwitches(0),
@@ -327,7 +330,8 @@
           exeMissingValid(false),
           cmdlineValid(false),
           updated(true),
-          killed(!llkTestWithKill) {
+          killed(!llkTestWithKill),
+          frozen(frozen) {
         memset(comm, '\0', sizeof(comm));
         setComm(_comm);
     }
@@ -373,6 +377,8 @@
         return uid;
     }
 
+    bool isFrozen() { return frozen; }
+
     void reset(void) {  // reset cache, if we detected pid rollover
         uid = -1;
         state = '?';
@@ -592,8 +598,9 @@
     tids.erase(tid);
 }
 
-proc* llkTidAlloc(pid_t tid, pid_t pid, pid_t ppid, const char* comm, int time, char state) {
-    auto it = tids.emplace(std::make_pair(tid, proc(tid, pid, ppid, comm, time, state)));
+proc* llkTidAlloc(pid_t tid, pid_t pid, pid_t ppid, const char* comm, int time, char state,
+                  bool frozen) {
+    auto it = tids.emplace(std::make_pair(tid, proc(tid, pid, ppid, comm, time, state, frozen)));
     return &it.first->second;
 }
 
@@ -1039,12 +1046,18 @@
                 continue;
             }
 
+            // Get the process cgroup
+            auto cgroup = ReadFile(piddir + "/cgroup");
+            auto frozen = cgroup.find(":freezer:/frozen") != std::string::npos;
+
             auto procp = llkTidLookup(tid);
             if (procp == nullptr) {
-                procp = llkTidAlloc(tid, pid, ppid, pdir, utime + stime, state);
+                procp = llkTidAlloc(tid, pid, ppid, pdir, utime + stime, state, frozen);
             } else {
                 // comm can change ...
                 procp->setComm(pdir);
+                // frozen can change, too...
+                procp->setFrozen(frozen);
                 procp->updated = true;
                 // pid/ppid/tid wrap?
                 if (((procp->update != prevUpdate) && (procp->update != llkUpdate)) ||
@@ -1084,6 +1097,9 @@
             if ((tid == myTid) || llkSkipPid(tid)) {
                 continue;
             }
+            if (procp->isFrozen()) {
+                break;
+            }
             if (llkSkipPpid(ppid)) {
                 break;
             }
@@ -1101,7 +1117,7 @@
 
             auto pprocp = llkTidLookup(ppid);
             if (pprocp == nullptr) {
-                pprocp = llkTidAlloc(ppid, ppid, 0, "", 0, '?');
+                pprocp = llkTidAlloc(ppid, ppid, 0, "", 0, '?', false);
             }
             if (pprocp) {
                 if (llkSkipPproc(pprocp, procp)) break;
diff --git a/llkd/llkd-debuggable.rc b/llkd/llkd-debuggable.rc
index 724cb5e..4b11b1c 100644
--- a/llkd/llkd-debuggable.rc
+++ b/llkd/llkd-debuggable.rc
@@ -13,7 +13,7 @@
     disabled
     user llkd
     group llkd readproc
-    capabilities KILL IPC_LOCK SYS_PTRACE DAC_OVERRIDE
+    capabilities KILL IPC_LOCK SYS_PTRACE DAC_OVERRIDE SYS_ADMIN
     file /dev/kmsg w
     file /proc/sysrq-trigger w
     writepid /dev/cpuset/system-background/tasks
diff --git a/llkd/tests/llkd_test.cpp b/llkd/tests/llkd_test.cpp
index 96079cc..475512c 100644
--- a/llkd/tests/llkd_test.cpp
+++ b/llkd/tests/llkd_test.cpp
@@ -89,7 +89,8 @@
         rest();
         std::string setprop("setprop ");
         // Manually check that SyS_openat is _added_ to the list when restarted
-        execute((setprop + LLK_CHECK_STACK_PROPERTY + " ,SyS_openat").c_str());
+        // 4.19+ kernels report __arm64_sys_openat b/147486902
+        execute((setprop + LLK_CHECK_STACK_PROPERTY + " ,SyS_openat,__arm64_sys_openat").c_str());
         rest();
         execute((setprop + LLK_ENABLE_WRITEABLE_PROPERTY + " false").c_str());
         rest();
diff --git a/property_service/property_info_checker/Android.bp b/property_service/property_info_checker/Android.bp
index 7d66199..65e660a 100644
--- a/property_service/property_info_checker/Android.bp
+++ b/property_service/property_info_checker/Android.bp
@@ -7,6 +7,7 @@
         "libpropertyinfoserializer",
         "libpropertyinfoparser",
         "libbase",
+        "liblog",
         "libsepol",
     ],
     srcs: ["property_info_checker.cpp"],
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 737fffe..6a6169c 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -551,6 +551,7 @@
     chown bluetooth bluetooth /data/misc/bluedroid/bt_config.conf
     mkdir /data/misc/bluetooth 0770 bluetooth bluetooth
     mkdir /data/misc/bluetooth/logs 0770 bluetooth bluetooth
+    mkdir /data/misc/credstore 0700 credstore credstore
     mkdir /data/misc/keystore 0700 keystore keystore
     mkdir /data/misc/gatekeeper 0700 system system
     mkdir /data/misc/keychain 0771 system system
@@ -588,11 +589,11 @@
     # profile file layout
     mkdir /data/misc/profiles 0771 system system
     mkdir /data/misc/profiles/cur 0771 system system
-    mkdir /data/misc/profiles/ref 0771 system system
+    mkdir /data/misc/profiles/ref 0770 system system
     mkdir /data/misc/profman 0770 system shell
     mkdir /data/misc/gcov 0770 root root
     mkdir /data/misc/installd 0700 root root
-    mkdir /data/misc/apexdata 0700 root root
+    mkdir /data/misc/apexdata 0711 root root
     mkdir /data/misc/apexrollback 0700 root root
 
     mkdir /data/preloads 0775 system system encryption=None
@@ -695,6 +696,10 @@
     mount none /data/user /data_mirror/data_ce/null bind rec
     mount none /data/user_de /data_mirror/data_de/null bind rec
 
+    # Create mirror directory for jit profiles
+    mkdir /data_mirror/cur_profiles 0700 root root
+    mount none /data/misc/profiles/cur /data_mirror/cur_profiles bind rec
+
     mkdir /data/cache 0770 system cache encryption=Require
     mkdir /data/cache/recovery 0770 system cache
     mkdir /data/cache/backup_stage 0700 system system
@@ -940,14 +945,33 @@
 on property:sys.sysctl.tcp_def_init_rwnd=*
     write /proc/sys/net/ipv4/tcp_default_init_rwnd ${sys.sysctl.tcp_def_init_rwnd}
 
-on property:security.perf_harden=0
+# perf_event_open syscall security:
+# Newer kernels have the ability to control the use of the syscall via SELinux
+# hooks. init tests for this, and sets sys_init.perf_lsm_hooks to 1 if the
+# kernel has the hooks. In this case, the system-wide perf_event_paranoid
+# sysctl is set to -1 (unrestricted use), and the SELinux policy is used for
+# controlling access. On older kernels, the paranoid value is the only means of
+# controlling access. It is normally 3 (allow only root), but the shell user
+# can lower it to 1 (allowing thread-scoped pofiling) via security.perf_harden.
+on property:sys.init.perf_lsm_hooks=1
+    write /proc/sys/kernel/perf_event_paranoid -1
+on property:security.perf_harden=0 && property:sys.init.perf_lsm_hooks=""
     write /proc/sys/kernel/perf_event_paranoid 1
+on property:security.perf_harden=1 && property:sys.init.perf_lsm_hooks=""
+    write /proc/sys/kernel/perf_event_paranoid 3
+
+# Additionally, simpleperf profiler uses debug.* and security.perf_harden
+# sysprops to be able to indirectly set these sysctls.
+on property:security.perf_harden=0
     write /proc/sys/kernel/perf_event_max_sample_rate ${debug.perf_event_max_sample_rate:-100000}
     write /proc/sys/kernel/perf_cpu_time_max_percent ${debug.perf_cpu_time_max_percent:-25}
     write /proc/sys/kernel/perf_event_mlock_kb ${debug.perf_event_mlock_kb:-516}
-
+# Default values.
 on property:security.perf_harden=1
-    write /proc/sys/kernel/perf_event_paranoid 3
+    write /proc/sys/kernel/perf_event_max_sample_rate 100000
+    write /proc/sys/kernel/perf_cpu_time_max_percent 25
+    write /proc/sys/kernel/perf_event_mlock_kb 516
+
 
 # on shutdown
 # In device's init.rc, this trigger can be used to do device-specific actions
diff --git a/shell_and_utilities/README.md b/shell_and_utilities/README.md
index d391cc1..3bee875 100644
--- a/shell_and_utilities/README.md
+++ b/shell_and_utilities/README.md
@@ -218,25 +218,28 @@
 
 bzip2: bzcat bzip2 bunzip2
 
+gavinhoward/bc: bc
+
 one-true-awk: awk
 
 toolbox: getevent getprop setprop start stop
 
-toybox: acpi base64 basename bc blkid blockdev cal cat chattr chcon chgrp
-chmod chown chroot chrt cksum clear cmp comm cp cpio cut date dd df
-diff dirname dmesg dos2unix du echo egrep env expand expr fallocate
-false fgrep file find flock fmt free freeramdisk fsfreeze getconf
-getenforce getfattr grep groups gunzip gzip head help hostname hwclock
-i2cdetect i2cdump i2cget i2cset iconv id ifconfig inotifyd insmod
-install ionice iorenice iotop kill killall ln load\_policy log logname
-losetup ls lsattr lsmod lsof lspci lsusb makedevs md5sum microcom
+toybox: acpi base64 basename blkid blockdev cal cat chattr chcon chgrp chmod
+chown chroot chrt cksum clear cmp comm cp cpio cut date dd devmem
+df diff dirname dmesg dos2unix du echo egrep env expand expr fallocate
+false fgrep file find flock fmt free freeramdisk fsfreeze fsync getconf
+getenforce getfattr getopt grep groups gunzip gzip head help hostname
+hwclock i2cdetect i2cdump i2cget i2cset iconv id ifconfig inotifyd
+insmod install ionice iorenice iotop kill killall ln load\_policy log
+logname losetup ls lsattr lsmod lsof lspci lsusb makedevs md5sum microcom
 mkdir mkfifo mknod mkswap mktemp modinfo modprobe more mount mountpoint
 mv nbd-client nc netcat netstat nice nl nohup nproc nsenter od partprobe
 paste patch pgrep pidof ping ping6 pivot\_root pkill pmap printenv
-printf prlimit ps pwd pwdx readlink realpath renice restorecon rev
-rfkill rm rmdir rmmod runcon sed sendevent seq setenforce setfattr
-setsid sha1sum sha224sum sha256sum sha384sum sha512sum sleep sort split
-stat strings stty swapoff swapon sync sysctl tac tail tar taskset tee
-time timeout top touch tr traceroute traceroute6 true truncate tty tunctl
-ulimit umount uname uniq unix2dos unlink unshare uptime usleep uudecode
-uuencode uuidgen vconfig vmstat watch wc which whoami xargs xxd yes zcat
+printf prlimit ps pwd pwdx readelf readlink realpath renice restorecon
+rev rfkill rm rmdir rmmod runcon sed sendevent seq setenforce setfattr
+setsid sha1sum sha224sum sha256sum sha384sum sha512sum sleep sort
+split stat strings stty swapoff swapon sync sysctl tac tail tar taskset
+tee time timeout top touch tr traceroute traceroute6 true truncate
+tty tunctl ulimit umount uname uniq unix2dos unlink unshare uptime
+usleep uudecode uuencode uuidgen vconfig vi vmstat watch wc which
+whoami xargs xxd yes zcat
diff --git a/trusty/confirmationui/.clang-format b/trusty/confirmationui/.clang-format
new file mode 100644
index 0000000..b0dc94c
--- /dev/null
+++ b/trusty/confirmationui/.clang-format
@@ -0,0 +1,10 @@
+BasedOnStyle: LLVM
+IndentWidth: 4
+UseTab: Never
+BreakBeforeBraces: Attach
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortIfStatementsOnASingleLine: true
+IndentCaseLabels: false
+ColumnLimit: 100
+PointerBindsToType: true
+SpacesBeforeTrailingComments: 2
diff --git a/trusty/confirmationui/Android.bp b/trusty/confirmationui/Android.bp
new file mode 100644
index 0000000..60e0e71
--- /dev/null
+++ b/trusty/confirmationui/Android.bp
@@ -0,0 +1,95 @@
+// Copyright (C) 2020 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.
+//
+
+// WARNING: Everything listed here will be built on ALL platforms,
+// including x86, the emulator, and the SDK.  Modules must be uniquely
+// named (liblights.panda), and must build everywhere, or limit themselves
+// to only building on ARM if they include assembly. Individual makefiles
+// are responsible for having their own logic, for fine-grained control.
+
+cc_binary {
+    name: "android.hardware.confirmationui@1.0-service.trusty",
+    relative_install_path: "hw",
+    vendor: true,
+    shared_libs: [
+        "android.hardware.confirmationui@1.0",
+        "android.hardware.confirmationui.not-so-secure-input",
+        "android.hardware.confirmationui@1.0-lib.trusty",
+        "libbase",
+        "libhidlbase",
+        "libutils",
+    ],
+
+    init_rc: ["android.hardware.confirmationui@1.0-service.trusty.rc"],
+
+    vintf_fragments: ["android.hardware.confirmationui@1.0-service.trusty.xml"],
+
+    srcs: [
+        "service.cpp",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-DTEEUI_USE_STD_VECTOR",
+    ],
+}
+
+cc_library {
+    name: "android.hardware.confirmationui@1.0-lib.trusty",
+    vendor: true,
+    shared_libs: [
+        "android.hardware.confirmationui@1.0",
+        "android.hardware.keymaster@4.0",
+        "libbase",
+        "libhidlbase",
+        "libteeui_hal_support",
+        "libtrusty",
+        "libutils",
+    ],
+
+    export_include_dirs: ["include"],
+
+    srcs: [
+        "TrustyApp.cpp",
+        "TrustyConfirmationUI.cpp",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-DTEEUI_USE_STD_VECTOR",
+    ],
+}
+
+cc_library {
+    name: "android.hardware.confirmationui.not-so-secure-input",
+    vendor: true,
+    shared_libs: [
+        "libbase",
+        "libcrypto",
+        "libteeui_hal_support",
+    ],
+
+    srcs: [
+        "NotSoSecureInput.cpp",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-DTEEUI_USE_STD_VECTOR",
+    ],
+}
\ No newline at end of file
diff --git a/trusty/confirmationui/NotSoSecureInput.cpp b/trusty/confirmationui/NotSoSecureInput.cpp
new file mode 100644
index 0000000..3d9a2d6
--- /dev/null
+++ b/trusty/confirmationui/NotSoSecureInput.cpp
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2020, 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 <android-base/logging.h>
+#include <endian.h>
+#include <memory>
+#include <openssl/hmac.h>
+#include <openssl/rand.h>
+#include <openssl/sha.h>
+#include <secure_input/evdev.h>
+#include <secure_input/secure_input_device.h>
+#include <teeui/utils.h>
+
+#include <initializer_list>
+
+using namespace secure_input;
+
+using teeui::AuthTokenKey;
+using teeui::ByteBufferProxy;
+using teeui::Hmac;
+using teeui::optional;
+using teeui::ResponseCode;
+using teeui::TestKeyBits;
+
+constexpr const auto kTestKey = AuthTokenKey::fill(static_cast<uint8_t>(TestKeyBits::BYTE));
+
+class SecureInputHMacer {
+  public:
+    static optional<Hmac> hmac256(const AuthTokenKey& key,
+                                  std::initializer_list<ByteBufferProxy> buffers) {
+        HMAC_CTX hmacCtx;
+        HMAC_CTX_init(&hmacCtx);
+        if (!HMAC_Init_ex(&hmacCtx, key.data(), key.size(), EVP_sha256(), nullptr)) {
+            return {};
+        }
+        for (auto& buffer : buffers) {
+            if (!HMAC_Update(&hmacCtx, buffer.data(), buffer.size())) {
+                return {};
+            }
+        }
+        Hmac result;
+        if (!HMAC_Final(&hmacCtx, result.data(), nullptr)) {
+            return {};
+        }
+        return result;
+    }
+};
+
+using HMac = teeui::HMac<SecureInputHMacer>;
+
+Nonce generateNonce() {
+    /*
+     * Completely random nonce.
+     * Running the secure input protocol from the HAL service is not secure
+     * because we don't trust the non-secure world (i.e., HLOS/Android/Linux). So
+     * using a constant "nonce" here does not weaken security. If this code runs
+     * on a truly trustworthy source of input events this function needs to return
+     * hight entropy nonces.
+     * As of this writing the call to RAND_bytes is commented, because the
+     * emulator this HAL service runs on does not have a good source of entropy.
+     * It would block the call to RAND_bytes indefinitely.
+     */
+    Nonce result{0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+                 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+                 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04};
+    // RAND_bytes(result.data(), result.size());
+    return result;
+}
+
+/**
+ * This is an implementation of the SecureInput protocol in unserspace. This is
+ * just an example and should not be used as is. The protocol implemented her
+ * should be used by a trusted input device that can assert user events with
+ * high assurance even if the HLOS kernel is compromised. A confirmationui HAL
+ * that links directly against this implementation is not secure and shal not be
+ * used on a production device.
+ */
+class NotSoSecureInput : public SecureInput {
+  public:
+    NotSoSecureInput(HsBeginCb hsBeginCb, HsFinalizeCb hsFinalizeCb, DeliverEventCb deliverEventCb,
+                     InputResultCb inputResultCb)
+        : hsBeginCb_{hsBeginCb}, hsFinalizeCb_{hsFinalizeCb}, deliverEventCb_{deliverEventCb},
+          inputResultCb_{inputResultCb}, discardEvents_{true} {}
+
+    operator bool() const override { return true; }
+
+    void handleEvent(const EventDev& evdev) override {
+        bool gotEvent;
+        input_event evt;
+        std::tie(gotEvent, evt) = evdev.readEvent();
+        while (gotEvent) {
+            if (!(discardEvents_) && evt.type == EV_KEY &&
+                (evt.code == KEY_POWER || evt.code == KEY_VOLUMEDOWN || evt.code == KEY_VOLUMEUP) &&
+                evt.value == 1) {
+                DTupKeyEvent event = DTupKeyEvent::RESERVED;
+
+                // Translate the event code into DTupKeyEvent which the TA understands.
+                switch (evt.code) {
+                case KEY_POWER:
+                    event = DTupKeyEvent::PWR;
+                    break;
+                case KEY_VOLUMEDOWN:
+                    event = DTupKeyEvent::VOL_DOWN;
+                    break;
+                case KEY_VOLUMEUP:
+                    event = DTupKeyEvent::VOL_UP;
+                    break;
+                }
+
+                // The event goes into the HMAC in network byte order.
+                uint32_t keyEventBE = htobe32(static_cast<uint32_t>(event));
+                auto signature = HMac::hmac256(kTestKey, kConfirmationUIEventLabel,
+                                               teeui::bytesCast(keyEventBE), nCi_);
+
+                teeui::ResponseCode rc;
+                InputResponse ir;
+                auto response = std::tie(rc, ir);
+                if (event != DTupKeyEvent::RESERVED) {
+                    response = deliverEventCb_(event, *signature);
+                    if (rc != ResponseCode::OK) {
+                        LOG(ERROR) << "DeliverInputEvent returned with " << uint32_t(rc);
+                        inputResultCb_(rc);
+                    } else {
+                        switch (ir) {
+                        case InputResponse::OK:
+                            inputResultCb_(rc);
+                            break;
+                        case InputResponse::PENDING_MORE:
+                            rc = performDTUPHandshake();
+                            if (rc != ResponseCode::OK) {
+                                inputResultCb_(rc);
+                            }
+                            break;
+                        case InputResponse::TIMED_OUT:
+                            inputResultCb_(rc);
+                            break;
+                        }
+                    }
+                }
+            }
+            std::tie(gotEvent, evt) = evdev.readEvent();
+        }
+    }
+
+    void start() override {
+        auto rc = performDTUPHandshake();
+        if (rc != ResponseCode::OK) {
+            inputResultCb_(rc);
+        }
+        discardEvents_ = false;
+    };
+
+  private:
+    teeui::ResponseCode performDTUPHandshake() {
+        ResponseCode rc;
+        LOG(INFO) << "Start handshake";
+        Nonce nCo;
+        std::tie(rc, nCo) = hsBeginCb_();
+        if (rc != ResponseCode::OK) {
+            LOG(ERROR) << "Failed to begin secure input handshake (" << uint32_t(rc) << ")";
+            return rc;
+        }
+
+        nCi_ = generateNonce();
+        rc =
+            hsFinalizeCb_(*HMac::hmac256(kTestKey, kConfirmationUIHandshakeLabel, nCo, nCi_), nCi_);
+
+        if (rc != ResponseCode::OK) {
+            LOG(ERROR) << "Failed to finalize secure input handshake (" << uint32_t(rc) << ")";
+            return rc;
+        }
+        return ResponseCode::OK;
+    }
+
+    HsBeginCb hsBeginCb_;
+    HsFinalizeCb hsFinalizeCb_;
+    DeliverEventCb deliverEventCb_;
+    InputResultCb inputResultCb_;
+
+    std::atomic_bool discardEvents_;
+    Nonce nCi_;
+};
+
+namespace secure_input {
+
+std::shared_ptr<SecureInput> createSecureInput(SecureInput::HsBeginCb hsBeginCb,
+                                               SecureInput::HsFinalizeCb hsFinalizeCb,
+                                               SecureInput::DeliverEventCb deliverEventCb,
+                                               SecureInput::InputResultCb inputResultCb) {
+    return std::make_shared<NotSoSecureInput>(hsBeginCb, hsFinalizeCb, deliverEventCb,
+                                              inputResultCb);
+}
+
+}  // namespace secure_input
diff --git a/trusty/confirmationui/README b/trusty/confirmationui/README
new file mode 100644
index 0000000..45d4e76
--- /dev/null
+++ b/trusty/confirmationui/README
@@ -0,0 +1,20 @@
+## Secure UI Architecture
+
+To implement confirmationui a secure UI architecture is required. This entails a way
+to display the confirmation dialog driven by a reduced trusted computing base, typically
+a trusted execution environment (TEE), without having to rely on Linux and the Android
+system for integrity and authenticity of input events. This implementation provides
+neither. But it provides most of the functionlity required to run a full Android Protected
+Confirmation feature when integrated into a secure UI architecture.
+
+## Secure input (NotSoSecureInput)
+
+This implementation does not provide any security guaranties.
+The input method (NotSoSecureInput) runs a cryptographic protocols that is
+sufficiently secure IFF the end point is implemented on a trustworthy
+secure input device. But since the endpoint is currently in the HAL
+service itself this implementation is not secure.
+
+NOTE that a secure input device end point needs a good source of entropy
+for generating nonces. The current implementation (NotSoSecureInput.cpp#generateNonce)
+uses a constant nonce.
\ No newline at end of file
diff --git a/trusty/confirmationui/TrustyApp.cpp b/trusty/confirmationui/TrustyApp.cpp
new file mode 100644
index 0000000..e4c68f9
--- /dev/null
+++ b/trusty/confirmationui/TrustyApp.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2020, 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 "TrustyApp.h"
+
+#include <android-base/logging.h>
+#include <sys/uio.h>
+#include <trusty/tipc.h>
+
+namespace android {
+namespace trusty {
+
+// 0x1000 is the message buffer size but we need to leave some space for a protocol header.
+// This assures that packets can always be read/written in one read/write operation.
+static constexpr const uint32_t kPacketSize = 0x1000 - 32;
+
+enum class PacketType : uint32_t {
+    SND,
+    RCV,
+    ACK,
+};
+
+struct PacketHeader {
+    PacketType type;
+    uint32_t remaining;
+};
+
+const char* toString(PacketType t) {
+    switch (t) {
+    case PacketType::SND:
+        return "SND";
+    case PacketType::RCV:
+        return "RCV";
+    case PacketType::ACK:
+        return "ACK";
+    default:
+        return "UNKNOWN";
+    }
+}
+
+static constexpr const uint32_t kHeaderSize = sizeof(PacketHeader);
+static constexpr const uint32_t kPayloadSize = kPacketSize - kHeaderSize;
+
+ssize_t TrustyRpc(int handle, const uint8_t* obegin, const uint8_t* oend, uint8_t* ibegin,
+                  uint8_t* iend) {
+    while (obegin != oend) {
+        PacketHeader header = {
+            .type = PacketType::SND,
+            .remaining = uint32_t(oend - obegin),
+        };
+        uint32_t body_size = std::min(kPayloadSize, header.remaining);
+        iovec iov[] = {
+            {
+                .iov_base = &header,
+                .iov_len = kHeaderSize,
+            },
+            {
+                .iov_base = const_cast<uint8_t*>(obegin),
+                .iov_len = body_size,
+            },
+        };
+        int rc = writev(handle, iov, 2);
+        if (!rc) {
+            PLOG(ERROR) << "Error sending SND message. " << rc;
+            return rc;
+        }
+
+        obegin += body_size;
+
+        rc = read(handle, &header, kHeaderSize);
+        if (!rc) {
+            PLOG(ERROR) << "Error reading ACK. " << rc;
+            return rc;
+        }
+
+        if (header.type != PacketType::ACK || header.remaining != oend - obegin) {
+            LOG(ERROR) << "malformed ACK";
+            return -1;
+        }
+    }
+
+    ssize_t remaining = 0;
+    auto begin = ibegin;
+    do {
+        PacketHeader header = {
+            .type = PacketType::RCV,
+            .remaining = 0,
+        };
+
+        iovec iov[] = {
+            {
+                .iov_base = &header,
+                .iov_len = kHeaderSize,
+            },
+            {
+                .iov_base = begin,
+                .iov_len = uint32_t(iend - begin),
+            },
+        };
+
+        ssize_t rc = writev(handle, iov, 1);
+        if (!rc) {
+            PLOG(ERROR) << "Error sending RCV message. " << rc;
+            return rc;
+        }
+
+        rc = readv(handle, iov, 2);
+        if (rc < 0) {
+            PLOG(ERROR) << "Error reading response. " << rc;
+            return rc;
+        }
+
+        uint32_t body_size = std::min(kPayloadSize, header.remaining);
+        if (body_size != rc - kHeaderSize) {
+            LOG(ERROR) << "Unexpected amount of data: " << rc;
+            return -1;
+        }
+
+        remaining = header.remaining - body_size;
+        begin += body_size;
+    } while (remaining);
+
+    return begin - ibegin;
+}
+
+TrustyApp::TrustyApp(const std::string& path, const std::string& appname)
+    : handle_(kInvalidHandle) {
+    handle_ = tipc_connect(path.c_str(), appname.c_str());
+    if (handle_ == kInvalidHandle) {
+        LOG(ERROR) << AT << "failed to connect to Trusty TA \"" << appname << "\" using dev:"
+                   << "\"" << path << "\"";
+    }
+    LOG(INFO) << AT << "succeeded to connect to Trusty TA \"" << appname << "\"";
+}
+TrustyApp::~TrustyApp() {
+    if (handle_ != kInvalidHandle) {
+        tipc_close(handle_);
+    }
+    LOG(INFO) << "Done shutting down TrustyApp";
+}
+
+}  // namespace trusty
+}  // namespace android
diff --git a/trusty/confirmationui/TrustyApp.h b/trusty/confirmationui/TrustyApp.h
new file mode 100644
index 0000000..05a25f6
--- /dev/null
+++ b/trusty/confirmationui/TrustyApp.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2020, 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.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+#include <errno.h>
+#include <poll.h>
+#include <stdio.h>
+#include <sys/eventfd.h>
+#include <sys/stat.h>
+#include <teeui/msg_formatting.h>
+#include <trusty/tipc.h>
+#include <unistd.h>
+
+#include <fstream>
+#include <functional>
+#include <future>
+#include <iostream>
+#include <sstream>
+#include <thread>
+#include <vector>
+
+#define AT __FILE__ ":" << __LINE__ << ": "
+
+namespace android {
+namespace trusty {
+
+using ::teeui::Message;
+using ::teeui::msg2tuple_t;
+using ::teeui::ReadStream;
+using ::teeui::WriteStream;
+
+#ifndef TEEUI_USE_STD_VECTOR
+/*
+ * TEEUI_USE_STD_VECTOR makes certain wire types like teeui::MsgString and
+ * teeui::MsgVector be aliases for std::vector. This is required for thread safe
+ * message serialization. Always compile this with -DTEEUI_USE_STD_VECTOR set in
+ * CFLAGS of the HAL service.
+ */
+#error "Must be compiled with -DTEEUI_USE_STD_VECTOR."
+#endif
+
+enum class TrustyAppError : int32_t {
+    OK,
+    ERROR = -1,
+    MSG_TOO_LONG = -2,
+};
+
+/*
+ * There is a hard limitation of 0x1800 bytes for the to-be-signed message size. The protocol
+ * overhead is limited, so that 0x2000 is a buffer size that will be sufficient in any benign
+ * mode of operation.
+ */
+static constexpr const size_t kSendBufferSize = 0x2000;
+
+ssize_t TrustyRpc(int handle, const uint8_t* obegin, const uint8_t* oend, uint8_t* ibegin,
+                  uint8_t* iend);
+
+class TrustyApp {
+  private:
+    int handle_;
+    static constexpr const int kInvalidHandle = -1;
+    /*
+     * This mutex serializes communication with the trusted app, not handle_.
+     * Calling issueCmd during construction or deletion is undefined behavior.
+     */
+    std::mutex mutex_;
+
+  public:
+    TrustyApp(const std::string& path, const std::string& appname);
+    ~TrustyApp();
+
+    template <typename Request, typename Response, typename... T>
+    std::tuple<TrustyAppError, msg2tuple_t<Response>> issueCmd(const T&... args) {
+        std::lock_guard<std::mutex> lock(mutex_);
+
+        if (handle_ == kInvalidHandle) {
+            LOG(ERROR) << "TrustyApp not connected";
+            return {TrustyAppError::ERROR, {}};
+        }
+
+        uint8_t buffer[kSendBufferSize];
+        WriteStream out(buffer);
+
+        out = write(Request(), out, args...);
+        if (!out) {
+            LOG(ERROR) << AT << "send command failed: message formatting";
+            return {TrustyAppError::MSG_TOO_LONG, {}};
+        }
+
+        auto rc = TrustyRpc(handle_, &buffer[0], const_cast<const uint8_t*>(out.pos()), &buffer[0],
+                            &buffer[kSendBufferSize]);
+        if (rc < 0) return {TrustyAppError::ERROR, {}};
+
+        ReadStream in(&buffer[0], rc);
+        auto result = read(Response(), in);
+        if (!std::get<0>(result)) {
+            LOG(ERROR) << "send command failed: message parsing";
+            return {TrustyAppError::ERROR, {}};
+        }
+
+        return {std::get<0>(result) ? TrustyAppError::OK : TrustyAppError::ERROR,
+                tuple_tail(std::move(result))};
+    }
+
+    template <typename Request, typename... T> TrustyAppError issueCmd(const T&... args) {
+        std::lock_guard<std::mutex> lock(mutex_);
+
+        if (handle_ == kInvalidHandle) {
+            LOG(ERROR) << "TrustyApp not connected";
+            return TrustyAppError::ERROR;
+        }
+
+        uint8_t buffer[kSendBufferSize];
+        WriteStream out(buffer);
+
+        out = write(Request(), out, args...);
+        if (!out) {
+            LOG(ERROR) << AT << "send command failed: message formatting";
+            return TrustyAppError::MSG_TOO_LONG;
+        }
+
+        auto rc = TrustyRpc(handle_, &buffer[0], const_cast<const uint8_t*>(out.pos()), &buffer[0],
+                            &buffer[kSendBufferSize]);
+        if (rc < 0) {
+            LOG(ERROR) << "send command failed: " << strerror(errno) << " (" << errno << ")";
+            return TrustyAppError::ERROR;
+        }
+
+        if (rc > 0) {
+            LOG(ERROR) << "Unexpected non zero length response";
+            return TrustyAppError::ERROR;
+        }
+        return TrustyAppError::OK;
+    }
+
+    operator bool() const { return handle_ != kInvalidHandle; }
+};
+
+}  // namespace trusty
+}  // namespace android
diff --git a/trusty/confirmationui/TrustyConfirmationUI.cpp b/trusty/confirmationui/TrustyConfirmationUI.cpp
new file mode 100644
index 0000000..6b25893
--- /dev/null
+++ b/trusty/confirmationui/TrustyConfirmationUI.cpp
@@ -0,0 +1,513 @@
+/*
+ *
+ * Copyright 2019, 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 "TrustyConfirmationUI.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/confirmationui/1.0/types.h>
+#include <android/hardware/keymaster/4.0/types.h>
+#include <fcntl.h>
+#include <linux/input.h>
+#include <poll.h>
+#include <pthread.h>
+#include <secure_input/evdev.h>
+#include <secure_input/secure_input_device.h>
+#include <secure_input/secure_input_proto.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <teeui/msg_formatting.h>
+#include <teeui/utils.h>
+#include <time.h>
+
+#include <atomic>
+#include <functional>
+#include <memory>
+#include <thread>
+#include <tuple>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace implementation {
+
+using namespace secure_input;
+
+using ::android::trusty::TrustyAppError;
+
+using ::teeui::AbortMsg;
+using ::teeui::DeliverTestCommandMessage;
+using ::teeui::DeliverTestCommandResponse;
+using ::teeui::FetchConfirmationResult;
+using ::teeui::MsgString;
+using ::teeui::MsgVector;
+using ::teeui::PromptUserConfirmationMsg;
+using ::teeui::PromptUserConfirmationResponse;
+using ::teeui::ResultMsg;
+
+using ::secure_input::createSecureInput;
+
+using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
+
+using ::std::tie;
+
+using TeeuiRc = ::teeui::ResponseCode;
+
+constexpr const char kTrustyDeviceName[] = "/dev/trusty-ipc-dev0";
+constexpr const char kConfirmationuiAppName[] = "com.android.trusty.confirmationui";
+
+namespace {
+
+class Finalize {
+  private:
+    std::function<void()> f_;
+
+  public:
+    Finalize(std::function<void()> f) : f_(f) {}
+    ~Finalize() {
+        if (f_) f_();
+    }
+    void release() { f_ = {}; }
+};
+
+ResponseCode convertRc(TeeuiRc trc) {
+    static_assert(
+        uint32_t(TeeuiRc::OK) == uint32_t(ResponseCode::OK) &&
+            uint32_t(TeeuiRc::Canceled) == uint32_t(ResponseCode::Canceled) &&
+            uint32_t(TeeuiRc::Aborted) == uint32_t(ResponseCode::Aborted) &&
+            uint32_t(TeeuiRc::OperationPending) == uint32_t(ResponseCode::OperationPending) &&
+            uint32_t(TeeuiRc::Ignored) == uint32_t(ResponseCode::Ignored) &&
+            uint32_t(TeeuiRc::SystemError) == uint32_t(ResponseCode::SystemError) &&
+            uint32_t(TeeuiRc::Unimplemented) == uint32_t(ResponseCode::Unimplemented) &&
+            uint32_t(TeeuiRc::Unexpected) == uint32_t(ResponseCode::Unexpected) &&
+            uint32_t(TeeuiRc::UIError) == uint32_t(ResponseCode::UIError) &&
+            uint32_t(TeeuiRc::UIErrorMissingGlyph) == uint32_t(ResponseCode::UIErrorMissingGlyph) &&
+            uint32_t(TeeuiRc::UIErrorMessageTooLong) ==
+                uint32_t(ResponseCode::UIErrorMessageTooLong) &&
+            uint32_t(TeeuiRc::UIErrorMalformedUTF8Encoding) ==
+                uint32_t(ResponseCode::UIErrorMalformedUTF8Encoding),
+        "teeui::ResponseCode and "
+        "::android::hardware::confirmationui::V1_0::Responsecude are out of "
+        "sync");
+    return ResponseCode(trc);
+}
+
+teeui::UIOption convertUIOption(UIOption uio) {
+    static_assert(uint32_t(UIOption::AccessibilityInverted) ==
+                          uint32_t(teeui::UIOption::AccessibilityInverted) &&
+                      uint32_t(UIOption::AccessibilityMagnified) ==
+                          uint32_t(teeui::UIOption::AccessibilityMagnified),
+                  "teeui::UIOPtion and ::android::hardware::confirmationui::V1_0::UIOption "
+                  "anre out of sync");
+    return teeui::UIOption(uio);
+}
+
+inline MsgString hidl2MsgString(const hidl_string& s) {
+    return {s.c_str(), s.c_str() + s.size()};
+}
+template <typename T> inline MsgVector<T> hidl2MsgVector(const hidl_vec<T>& v) {
+    return {v};
+}
+
+inline MsgVector<teeui::UIOption> hidl2MsgVector(const hidl_vec<UIOption>& v) {
+    MsgVector<teeui::UIOption> result(v.size());
+    for (unsigned int i = 0; i < v.size(); ++i) {
+        result[i] = convertUIOption(v[i]);
+    }
+    return result;
+}
+
+}  // namespace
+
+TrustyConfirmationUI::TrustyConfirmationUI()
+    : listener_state_(ListenerState::None), prompt_result_(ResponseCode::Ignored) {}
+
+TrustyConfirmationUI::~TrustyConfirmationUI() {
+    ListenerState state = listener_state_;
+    if (state == ListenerState::SetupDone || state == ListenerState::Interactive) {
+        abort();
+    }
+    if (state != ListenerState::None) {
+        callback_thread_.join();
+    }
+}
+
+std::tuple<TeeuiRc, MsgVector<uint8_t>, MsgVector<uint8_t>>
+TrustyConfirmationUI::promptUserConfirmation_(const MsgString& promptText,
+                                              const MsgVector<uint8_t>& extraData,
+                                              const MsgString& locale,
+                                              const MsgVector<teeui::UIOption>& uiOptions) {
+    std::unique_lock<std::mutex> stateLock(listener_state_lock_);
+    /*
+     * This is the main listener thread function. The listener thread life cycle
+     * is equivalent to the life cycle of a single confirmation request. The life
+     * cycle is devided in four phases.
+     *  * The starting phase:
+     *    * The Trusted App gets loaded and/or the connection to it gets established.
+     *    * A connection to the secure input device is established.
+     *    * The prompt is initiated. This sends all information required by the
+     *      confirmation dialog to the TA. The dialog is not yet displayed.
+     *    * An event loop is created.
+     *      * The event loop listens for user input events, fetches them from the
+     *        secure input device, and delivers them to the TA.
+     *    * All evdev devices are grabbed to give confirmationui exclusive access
+     *      to user input.
+     *
+     * Note: During the starting phase the hwbinder service thread is blocked and
+     * waiting for possible Errors. If the setup phase concludes sucessfully, the
+     * hwbinder service thread gets unblocked and returns successfully. Errors
+     * that occur after the first phase are delivered by callback interface.
+     *
+     *  * The 2nd phase - non interactive phase
+     *    * The event loop thread is started.
+     *    * After a grace period:
+     *      * A handshake between the secure input device SecureInput and the TA
+     *        is performed.
+     *      * The input event handler are armed to process user input events.
+     *
+     *  * The 3rd phase - interactive phase
+     *    * We wait to any external event
+     *      * Abort
+     *      * Secure user input asserted
+     *      * Secure input delivered (for non interactive VTS testing)
+     *    * The result is fetched from the TA.
+     *
+     *  * The 4th phase - cleanup
+     *    The cleanup phase is given by the scope of automatic variables created
+     *    in this function. The cleanup commences in reverse order of their creation.
+     *    Here is a list of more complex items in the order in which they go out of
+     *    scope
+     *    * finalizeSecureTouch - signals and joins the secure touch thread.
+     *    * eventloop - signals and joins the event loop thread. The event
+     *      handlers also own all EventDev instances which ungrab the event devices.
+     *      When the eventloop goes out of scope the EventDevs get destroyed
+     *      relinquishing the exclusive hold on the event devices.
+     *    * finalizeConfirmationPrompt - calls abort on the TA, making sure a
+     *      pending operation gets canceled. If the prompt concluded successfully this
+     *      is a spurious call but semantically a no op.
+     *    * secureInput - shuts down the connection to the secure input device
+     *      SecureInput.
+     *    * app - disconnects the TA. Since app is a shared pointer this may not
+     *      unload the app here. It is possible that more instances of the shared
+     *      pointer are held in TrustyConfirmationUI::deliverSecureInputEvent and
+     *      TrustyConfirmationUI::abort. But these instances are extremely short lived
+     *      and it is safe if they are destroyed by either.
+     *    * stateLock - unlocks the listener_state_lock_ if it happens to be held
+     *      at the time of return.
+     */
+
+    std::tuple<TeeuiRc, MsgVector<uint8_t>, MsgVector<uint8_t>> result;
+    TeeuiRc& rc = std::get<TeeuiRc>(result);
+    rc = TeeuiRc::SystemError;
+
+    listener_state_ = ListenerState::Starting;
+
+    auto app = std::make_shared<TrustyApp>(kTrustyDeviceName, kConfirmationuiAppName);
+    if (!app) return result;  // TeeuiRc::SystemError
+
+    app_ = app;
+
+    auto hsBegin = [&]() -> std::tuple<TeeuiRc, Nonce> {
+        auto [error, result] =
+            app->issueCmd<secure_input::InputHandshake, secure_input::InputHandshakeResponse>();
+        auto& [rc, nCo] = result;
+
+        if (error != TrustyAppError::OK || rc != TeeuiRc::OK) {
+            LOG(ERROR) << "Failed to begin secure input handshake (" << int32_t(error) << "/"
+                       << uint32_t(rc) << ")";
+            rc = error != TrustyAppError::OK ? TeeuiRc::SystemError : rc;
+        }
+        return result;
+    };
+
+    auto hsFinalize = [&](const Signature& sig, const Nonce& nCi) -> TeeuiRc {
+        auto [error, finalizeResponse] =
+            app->issueCmd<FinalizeInputSessionHandshake, FinalizeInputSessionHandshakeResponse>(
+                nCi, sig);
+        auto& [rc] = finalizeResponse;
+        if (error != TrustyAppError::OK || rc != TeeuiRc::OK) {
+            LOG(ERROR) << "Failed to finalize secure input handshake (" << int32_t(error) << "/"
+                       << uint32_t(rc) << ")";
+            rc = error != TrustyAppError::OK ? TeeuiRc::SystemError : rc;
+        }
+        return rc;
+    };
+
+    auto deliverInput = [&](DTupKeyEvent event,
+                            const Signature& sig) -> std::tuple<TeeuiRc, InputResponse> {
+        auto [error, result] =
+            app->issueCmd<DeliverInputEvent, DeliverInputEventResponse>(event, sig);
+        auto& [rc, ir] = result;
+        if (error != TrustyAppError::OK) {
+            LOG(ERROR) << "Failed to deliver input command";
+            rc = TeeuiRc::SystemError;
+        }
+        return result;
+    };
+
+    std::atomic<TeeuiRc> eventRC = TeeuiRc::OperationPending;
+    auto inputResult = [&](TeeuiRc rc) {
+        TeeuiRc expected = TeeuiRc::OperationPending;
+        if (eventRC.compare_exchange_strong(expected, rc)) {
+            listener_state_condv_.notify_all();
+        }
+    };
+
+    // create Secure Input device.
+    auto secureInput = createSecureInput(hsBegin, hsFinalize, deliverInput, inputResult);
+    if (!secureInput || !(*secureInput)) {
+        LOG(ERROR) << "Failed to open secure input device";
+        return result;  // TeeuiRc::SystemError;
+    }
+
+    Finalize finalizeConfirmationPrompt([app] {
+        LOG(INFO) << "Calling abort for cleanup";
+        app->issueCmd<AbortMsg>();
+    });
+
+    // initiate prompt
+    LOG(INFO) << "Initiating prompt";
+    TrustyAppError error;
+    auto initResponse = std::tie(rc);
+    std::tie(error, initResponse) =
+        app->issueCmd<PromptUserConfirmationMsg, PromptUserConfirmationResponse>(
+            promptText, extraData, locale, uiOptions);
+    if (error == TrustyAppError::MSG_TOO_LONG) {
+        LOG(ERROR) << "PromptUserConfirmationMsg failed: message too long";
+        rc = TeeuiRc::UIErrorMessageTooLong;
+        return result;
+    } else if (error != TrustyAppError::OK) {
+        LOG(ERROR) << "PromptUserConfirmationMsg failed: " << int32_t(error);
+        return result;  // TeeuiRc::SystemError;
+    }
+    if (rc != TeeuiRc::OK) {
+        LOG(ERROR) << "PromptUserConfirmationMsg failed: " << uint32_t(rc);
+        return result;
+    }
+
+    LOG(INFO) << "Grabbing event devices";
+    EventLoop eventloop;
+    bool grabbed =
+        grabAllEvDevsAndRegisterCallbacks(&eventloop, [&](short flags, const EventDev& evDev) {
+            if (!(flags & POLLIN)) return;
+            secureInput->handleEvent(evDev);
+        });
+
+    if (!grabbed) {
+        rc = TeeuiRc::SystemError;
+        return result;
+    }
+
+    abort_called_ = false;
+    secureInputDelivered_ = false;
+
+    //  ############################## Start 2nd Phase #############################################
+    listener_state_ = ListenerState::SetupDone;
+    stateLock.unlock();
+    listener_state_condv_.notify_all();
+
+    if (!eventloop.start()) {
+        rc = TeeuiRc::SystemError;
+        return result;
+    }
+
+    stateLock.lock();
+
+    LOG(INFO) << "going to sleep for the grace period";
+    auto then = std::chrono::system_clock::now() +
+                std::chrono::milliseconds(kUserPreInputGracePeriodMillis) +
+                std::chrono::microseconds(50);
+    listener_state_condv_.wait_until(stateLock, then, [&]() { return abort_called_; });
+    LOG(INFO) << "waking up";
+
+    if (abort_called_) {
+        LOG(ERROR) << "Abort called";
+        result = {TeeuiRc::Aborted, {}, {}};
+        return result;
+    }
+
+    LOG(INFO) << "Arming event poller";
+    // tell the event poller to act on received input events from now on.
+    secureInput->start();
+
+    //  ############################## Start 3rd Phase - interactive phase #########################
+    LOG(INFO) << "Transition to Interactive";
+    listener_state_ = ListenerState::Interactive;
+    stateLock.unlock();
+    listener_state_condv_.notify_all();
+
+    stateLock.lock();
+    listener_state_condv_.wait(stateLock, [&]() {
+        return eventRC != TeeuiRc::OperationPending || abort_called_ || secureInputDelivered_;
+    });
+    LOG(INFO) << "Listener waking up";
+    if (abort_called_) {
+        LOG(ERROR) << "Abort called";
+        result = {TeeuiRc::Aborted, {}, {}};
+        return result;
+    }
+
+    if (!secureInputDelivered_) {
+        if (eventRC != TeeuiRc::OK) {
+            LOG(ERROR) << "Bad input response";
+            result = {eventRC, {}, {}};
+            return result;
+        }
+    }
+
+    stateLock.unlock();
+
+    LOG(INFO) << "Fetching Result";
+    std::tie(error, result) = app->issueCmd<FetchConfirmationResult, ResultMsg>();
+    LOG(INFO) << "Result yields " << int32_t(error) << "/" << uint32_t(rc);
+    if (error != TrustyAppError::OK) {
+        result = {TeeuiRc::SystemError, {}, {}};
+    }
+    return result;
+
+    //  ############################## Start 4th Phase - cleanup ##################################
+}
+
+// Methods from ::android::hardware::confirmationui::V1_0::IConfirmationUI
+// follow.
+Return<ResponseCode> TrustyConfirmationUI::promptUserConfirmation(
+    const sp<IConfirmationResultCallback>& resultCB, const hidl_string& promptText,
+    const hidl_vec<uint8_t>& extraData, const hidl_string& locale,
+    const hidl_vec<UIOption>& uiOptions) {
+    std::unique_lock<std::mutex> stateLock(listener_state_lock_, std::defer_lock);
+    if (!stateLock.try_lock()) {
+        return ResponseCode::OperationPending;
+    }
+    switch (listener_state_) {
+    case ListenerState::None:
+        break;
+    case ListenerState::Starting:
+    case ListenerState::SetupDone:
+    case ListenerState::Interactive:
+        return ResponseCode::OperationPending;
+    case ListenerState::Terminating:
+        callback_thread_.join();
+        listener_state_ = ListenerState::None;
+        break;
+    default:
+        return ResponseCode::Unexpected;
+    }
+
+    assert(listener_state_ == ListenerState::None);
+
+    callback_thread_ = std::thread(
+        [this](sp<IConfirmationResultCallback> resultCB, hidl_string promptText,
+               hidl_vec<uint8_t> extraData, hidl_string locale, hidl_vec<UIOption> uiOptions) {
+            auto [trc, msg, token] =
+                promptUserConfirmation_(hidl2MsgString(promptText), hidl2MsgVector(extraData),
+                                        hidl2MsgString(locale), hidl2MsgVector(uiOptions));
+            bool do_callback = (listener_state_ == ListenerState::Interactive ||
+                                listener_state_ == ListenerState::SetupDone) &&
+                               resultCB;
+            prompt_result_ = convertRc(trc);
+            listener_state_ = ListenerState::Terminating;
+            if (do_callback) {
+                auto error = resultCB->result(prompt_result_, msg, token);
+                if (!error.isOk()) {
+                    LOG(ERROR) << "Result callback failed " << error.description();
+                }
+            } else {
+                listener_state_condv_.notify_all();
+            }
+        },
+        resultCB, promptText, extraData, locale, uiOptions);
+
+    listener_state_condv_.wait(stateLock, [this] {
+        return listener_state_ == ListenerState::SetupDone ||
+               listener_state_ == ListenerState::Interactive ||
+               listener_state_ == ListenerState::Terminating;
+    });
+    if (listener_state_ == ListenerState::Terminating) {
+        callback_thread_.join();
+        listener_state_ = ListenerState::None;
+        return prompt_result_;
+    }
+    return ResponseCode::OK;
+}
+
+Return<ResponseCode>
+TrustyConfirmationUI::deliverSecureInputEvent(const HardwareAuthToken& secureInputToken) {
+    ResponseCode rc = ResponseCode::Ignored;
+    {
+        /*
+         * deliverSecureInputEvent is only used by the VTS test to mock human input. A correct
+         * implementation responds with a mock confirmation token signed with a test key. The
+         * problem is that the non interactive grace period was not formalized in the HAL spec,
+         * so that the VTS test does not account for the grace period. (It probably should.)
+         * This means we can only pass the VTS test if we block until the grace period is over
+         * (SetupDone -> Interactive) before we deliver the input event.
+         *
+         * The true secure input is delivered by a different mechanism and gets ignored -
+         * not queued - until the grace period is over.
+         *
+         */
+        std::unique_lock<std::mutex> stateLock(listener_state_lock_);
+        listener_state_condv_.wait(stateLock,
+                                   [this] { return listener_state_ != ListenerState::SetupDone; });
+
+        if (listener_state_ != ListenerState::Interactive) return ResponseCode::Ignored;
+        auto sapp = app_.lock();
+        if (!sapp) return ResponseCode::Ignored;
+        auto [error, response] =
+            sapp->issueCmd<DeliverTestCommandMessage, DeliverTestCommandResponse>(
+                static_cast<teeui::TestModeCommands>(secureInputToken.challenge));
+        if (error != TrustyAppError::OK) return ResponseCode::SystemError;
+        auto& [trc] = response;
+        if (trc != TeeuiRc::Ignored) secureInputDelivered_ = true;
+        rc = convertRc(trc);
+    }
+    if (secureInputDelivered_) listener_state_condv_.notify_all();
+    // VTS test expect an OK response if the event was successfully delivered.
+    // But since the TA returns the callback response now, we have to translate
+    // Canceled into OK. Canceled is only returned if the delivered event canceled
+    // the operation, which means that the event was successfully delivered. Thus
+    // we return OK.
+    if (rc == ResponseCode::Canceled) return ResponseCode::OK;
+    return rc;
+}
+
+Return<void> TrustyConfirmationUI::abort() {
+    {
+        std::unique_lock<std::mutex> stateLock(listener_state_lock_);
+        if (listener_state_ == ListenerState::SetupDone ||
+            listener_state_ == ListenerState::Interactive) {
+            auto sapp = app_.lock();
+            if (sapp) sapp->issueCmd<AbortMsg>();
+            abort_called_ = true;
+        }
+    }
+    listener_state_condv_.notify_all();
+    return Void();
+}
+
+android::sp<IConfirmationUI> createTrustyConfirmationUI() {
+    return new TrustyConfirmationUI();
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
diff --git a/trusty/confirmationui/TrustyConfirmationUI.h b/trusty/confirmationui/TrustyConfirmationUI.h
new file mode 100644
index 0000000..3a7c7ef
--- /dev/null
+++ b/trusty/confirmationui/TrustyConfirmationUI.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2020, 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 ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_TRUSTY_CONFIRMATIONUI_H
+#define ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_TRUSTY_CONFIRMATIONUI_H
+
+#include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
+#include <android/hardware/keymaster/4.0/types.h>
+#include <hidl/Status.h>
+
+#include <atomic>
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <teeui/generic_messages.h>
+#include <thread>
+
+#include "TrustyApp.h"
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using ::android::trusty::TrustyApp;
+
+class TrustyConfirmationUI : public IConfirmationUI {
+  public:
+    TrustyConfirmationUI();
+    virtual ~TrustyConfirmationUI();
+    // Methods from ::android::hardware::confirmationui::V1_0::IConfirmationUI
+    // follow.
+    Return<ResponseCode> promptUserConfirmation(const sp<IConfirmationResultCallback>& resultCB,
+                                                const hidl_string& promptText,
+                                                const hidl_vec<uint8_t>& extraData,
+                                                const hidl_string& locale,
+                                                const hidl_vec<UIOption>& uiOptions) override;
+    Return<ResponseCode> deliverSecureInputEvent(
+        const ::android::hardware::keymaster::V4_0::HardwareAuthToken& secureInputToken) override;
+    Return<void> abort() override;
+
+  private:
+    std::weak_ptr<TrustyApp> app_;
+    std::thread callback_thread_;
+
+    enum class ListenerState : uint32_t {
+        None,
+        Starting,
+        SetupDone,
+        Interactive,
+        Terminating,
+    };
+
+    /*
+     * listener_state is protected by listener_state_lock. It makes transitions between phases
+     * of the confirmation operation atomic.
+     * (See TrustyConfirmationUI.cpp#promptUserConfirmation_ for details about operation phases)
+     */
+    ListenerState listener_state_;
+    /*
+     * abort_called_ is also protected by listener_state_lock_ and indicates that the HAL user
+     * called abort.
+     */
+    bool abort_called_;
+    std::mutex listener_state_lock_;
+    std::condition_variable listener_state_condv_;
+    ResponseCode prompt_result_;
+    bool secureInputDelivered_;
+
+    std::tuple<teeui::ResponseCode, teeui::MsgVector<uint8_t>, teeui::MsgVector<uint8_t>>
+    promptUserConfirmation_(const teeui::MsgString& promptText,
+                            const teeui::MsgVector<uint8_t>& extraData,
+                            const teeui::MsgString& locale,
+                            const teeui::MsgVector<teeui::UIOption>& uiOptions);
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_TRUSTY_CONFIRMATIONUI_H
diff --git a/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.rc b/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.rc
new file mode 100644
index 0000000..dc7a03b
--- /dev/null
+++ b/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.rc
@@ -0,0 +1,4 @@
+service confirmationui-1-0 /vendor/bin/hw/android.hardware.confirmationui@1.0-service.trusty
+    class hal
+    user nobody
+    group drmrpc input
diff --git a/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.xml b/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.xml
new file mode 100644
index 0000000..9008b87
--- /dev/null
+++ b/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.confirmationui</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+        <name>IConfirmationUI</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/trusty/confirmationui/include/TrustyConfirmationuiHal.h b/trusty/confirmationui/include/TrustyConfirmationuiHal.h
new file mode 100644
index 0000000..2ab9389
--- /dev/null
+++ b/trusty/confirmationui/include/TrustyConfirmationuiHal.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2020, 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.
+ */
+
+#pragma once
+
+#include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace implementation {
+
+android::sp<IConfirmationUI> createTrustyConfirmationUI();
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
diff --git a/trusty/confirmationui/service.cpp b/trusty/confirmationui/service.cpp
new file mode 100644
index 0000000..dd7e84b
--- /dev/null
+++ b/trusty/confirmationui/service.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020, 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 <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include <TrustyConfirmationuiHal.h>
+
+using android::sp;
+using android::hardware::confirmationui::V1_0::implementation::createTrustyConfirmationUI;
+
+int main() {
+    ::android::hardware::configureRpcThreadpool(1, true /*willJoinThreadpool*/);
+    auto service = createTrustyConfirmationUI();
+    auto status = service->registerAsService();
+    if (status != android::OK) {
+        LOG(FATAL) << "Could not register service for ConfirmationUI 1.0 (" << status << ")";
+        return -1;
+    }
+    ::android::hardware::joinRpcThreadpool();
+    return -1;
+}