Merge "Add the rough toybox version numbers to the docs."
diff --git a/adb/Android.bp b/adb/Android.bp
index 87ac54d..8addf95 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -117,6 +117,7 @@
     static_libs: [
         "libadb_crypto",
         "libadb_pairing_connection",
+        "libadb_sysdeps",
         "libadb_tls_connection",
         "libadbd",
         "libadbd_core",
@@ -167,6 +168,7 @@
     "services.cpp",
     "sockets.cpp",
     "socket_spec.cpp",
+    "sysdeps/env.cpp",
     "sysdeps/errno.cpp",
     "transport.cpp",
     "transport_fd.cpp",
@@ -261,6 +263,43 @@
     ],
 }
 
+cc_library {
+    name: "libadb_sysdeps",
+    defaults: ["adb_defaults"],
+    recovery_available: true,
+    host_supported: true,
+    compile_multilib: "both",
+    min_sdk_version: "apex_inherit",
+
+    srcs: [
+        "sysdeps/env.cpp",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "liblog",
+    ],
+
+    target: {
+        windows: {
+            enabled: true,
+            ldflags: ["-municode"],
+        },
+    },
+
+    export_include_dirs: ["."],
+
+    visibility: [
+        "//system/core/adb:__subpackages__",
+        "//bootable/recovery/minadbd:__subpackages__",
+    ],
+
+    apex_available: [
+        "com.android.adbd",
+        "test_com.android.adbd",
+    ],
+}
+
 cc_test_host {
     name: "adb_test",
     defaults: ["adb_defaults"],
@@ -274,6 +313,7 @@
         "libadb_pairing_auth_static",
         "libadb_pairing_connection_static",
         "libadb_protos_static",
+        "libadb_sysdeps",
         "libadb_tls_connection_static",
         "libbase",
         "libcutils",
@@ -330,6 +370,7 @@
         "libadb_pairing_auth",
         "libadb_pairing_connection",
         "libadb_protos",
+        "libadb_sysdeps",
         "libadb_tls_connection",
         "libandroidfw",
         "libapp_processes_protos_full",
@@ -831,6 +872,7 @@
         "libadb_pairing_auth_static",
         "libadb_pairing_connection_static",
         "libadb_protos_static",
+        "libadb_sysdeps",
         "libadb_tls_connection_static",
         "libandroidfw",
         "libbase",
diff --git a/adb/crypto/Android.bp b/adb/crypto/Android.bp
index 9d14b03..e2c27f1 100644
--- a/adb/crypto/Android.bp
+++ b/adb/crypto/Android.bp
@@ -48,6 +48,7 @@
 
     shared_libs: [
         "libadb_protos",
+        "libadb_sysdeps",
         "libbase",
         "liblog",
         "libcrypto",
@@ -76,5 +77,6 @@
 
     static_libs: [
         "libadb_protos_static",
+        "libadb_sysdeps",
     ],
 }
diff --git a/adb/crypto/rsa_2048_key.cpp b/adb/crypto/rsa_2048_key.cpp
index 7911af9..6d9ee30 100644
--- a/adb/crypto/rsa_2048_key.cpp
+++ b/adb/crypto/rsa_2048_key.cpp
@@ -20,32 +20,11 @@
 #include <crypto_utils/android_pubkey.h>
 #include <openssl/bn.h>
 #include <openssl/rsa.h>
+#include <sysdeps/env.h>
 
 namespace adb {
 namespace crypto {
 
-namespace {
-std::string get_user_info() {
-    std::string hostname;
-    if (getenv("HOSTNAME")) hostname = getenv("HOSTNAME");
-#if !defined(_WIN32)
-    char buf[64];
-    if (hostname.empty() && gethostname(buf, sizeof(buf)) != -1) hostname = buf;
-#endif
-    if (hostname.empty()) hostname = "unknown";
-
-    std::string username;
-    if (getenv("LOGNAME")) username = getenv("LOGNAME");
-#if !defined(_WIN32)
-    if (username.empty() && getlogin()) username = getlogin();
-#endif
-    if (username.empty()) hostname = "unknown";
-
-    return " " + username + "@" + hostname;
-}
-
-}  // namespace
-
 bool CalculatePublicKey(std::string* out, RSA* private_key) {
     uint8_t binary_key_data[ANDROID_PUBKEY_ENCODED_SIZE];
     if (!android_pubkey_encode(private_key, binary_key_data, sizeof(binary_key_data))) {
@@ -63,7 +42,10 @@
     size_t actual_length = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(out->data()), binary_key_data,
                                            sizeof(binary_key_data));
     out->resize(actual_length);
-    out->append(get_user_info());
+    out->append(" ");
+    out->append(sysdeps::GetLoginNameUTF8());
+    out->append("@");
+    out->append(sysdeps::GetHostNameUTF8());
     return true;
 }
 
diff --git a/adb/crypto/tests/Android.bp b/adb/crypto/tests/Android.bp
index b32dcf7..b041055 100644
--- a/adb/crypto/tests/Android.bp
+++ b/adb/crypto/tests/Android.bp
@@ -35,6 +35,7 @@
     static_libs: [
         "libadb_crypto_static",
         "libadb_protos_static",
+        "libadb_sysdeps",
     ],
 
     test_suites: ["device-tests"],
diff --git a/adb/sysdeps/env.cpp b/adb/sysdeps/env.cpp
new file mode 100644
index 0000000..4058728
--- /dev/null
+++ b/adb/sysdeps/env.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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 "sysdeps/env.h"
+
+#ifdef _WIN32
+#include <lmcons.h>
+#include <windows.h>
+#endif  // _WIN32
+
+#include <android-base/utf8.h>
+
+namespace adb {
+namespace sysdeps {
+
+std::optional<std::string> GetEnvironmentVariable(std::string_view var) {
+    if (var.empty()) {
+        return std::nullopt;
+    }
+
+#ifdef _WIN32
+    constexpr size_t kMaxEnvVarSize = 32767;
+    wchar_t wbuf[kMaxEnvVarSize];
+    std::wstring wvar;
+    if (!android::base::UTF8ToWide(var.data(), &wvar)) {
+        return std::nullopt;
+    }
+
+    auto sz = ::GetEnvironmentVariableW(wvar.data(), wbuf, sizeof(wbuf));
+    if (sz == 0) {
+        return std::nullopt;
+    }
+
+    std::string val;
+    if (!android::base::WideToUTF8(wbuf, &val)) {
+        return std::nullopt;
+    }
+
+    return std::make_optional(val);
+#else  // !_WIN32
+    const char* val = getenv(var.data());
+    if (val == nullptr) {
+        return std::nullopt;
+    }
+
+    return std::make_optional(std::string(val));
+#endif
+}
+
+#ifdef _WIN32
+constexpr char kHostNameEnvVar[] = "COMPUTERNAME";
+constexpr char kUserNameEnvVar[] = "USERNAME";
+#else
+constexpr char kHostNameEnvVar[] = "HOSTNAME";
+constexpr char kUserNameEnvVar[] = "LOGNAME";
+#endif
+
+std::string GetHostNameUTF8() {
+    const auto hostName = GetEnvironmentVariable(kHostNameEnvVar);
+    if (hostName && !hostName->empty()) {
+        return *hostName;
+    }
+
+#ifdef _WIN32
+    wchar_t wbuf[MAX_COMPUTERNAME_LENGTH + 1];
+    DWORD size = sizeof(wbuf);
+    if (!GetComputerNameW(wbuf, &size) || size == 0) {
+        return "";
+    }
+
+    std::string name;
+    if (!android::base::WideToUTF8(wbuf, &name)) {
+        return "";
+    }
+
+    return name;
+#else   // !_WIN32
+    char buf[256];
+    return (gethostname(buf, sizeof(buf)) == -1) ? "" : buf;
+#endif  // _WIN32
+}
+
+std::string GetLoginNameUTF8() {
+    const auto userName = GetEnvironmentVariable(kUserNameEnvVar);
+    if (userName && !userName->empty()) {
+        return *userName;
+    }
+
+#ifdef _WIN32
+    wchar_t wbuf[UNLEN + 1];
+    DWORD size = sizeof(wbuf);
+    if (!GetUserNameW(wbuf, &size) || size == 0) {
+        return "";
+    }
+
+    std::string login;
+    if (!android::base::WideToUTF8(wbuf, &login)) {
+        return "";
+    }
+
+    return login;
+#else   // !_WIN32
+    const char* login = getlogin();
+    return login ? login : "";
+#endif  // _WIN32
+}
+
+}  // namespace sysdeps
+}  // namespace adb
diff --git a/adb/sysdeps/env.h b/adb/sysdeps/env.h
new file mode 100644
index 0000000..b39b675
--- /dev/null
+++ b/adb/sysdeps/env.h
@@ -0,0 +1,35 @@
+/*
+ * 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 <string>
+
+namespace adb {
+namespace sysdeps {
+
+// Attempts to retrieve the environment variable value for |var|. Returns std::nullopt
+// if unset.
+std::optional<std::string> GetEnvironmentVariableUTF8(std::string_view var);
+
+// Gets the host name of the system. Returns empty string on failure.
+std::string GetHostNameUTF8();
+// Gets the current login user. Returns empty string on failure.
+std::string GetLoginNameUTF8();
+
+}  // namespace sysdeps
+}  // namespace adb
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index be82bc0..217a6b7 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -1010,55 +1010,6 @@
     return _fh_to_int(f);
 }
 
-static bool isBlankStr(const char* str) {
-    for (; *str != '\0'; ++str) {
-        if (!isblank(*str)) {
-            return false;
-        }
-    }
-    return true;
-}
-
-int adb_gethostname(char* name, size_t len) {
-    const char* computerName = adb_getenv("COMPUTERNAME");
-    if (computerName && !isBlankStr(computerName)) {
-        strncpy(name, computerName, len);
-        name[len - 1] = '\0';
-        return 0;
-    }
-
-    wchar_t buffer[MAX_COMPUTERNAME_LENGTH + 1];
-    DWORD size = sizeof(buffer);
-    if (!GetComputerNameW(buffer, &size)) {
-        return -1;
-    }
-    std::string name_utf8;
-    if (!android::base::WideToUTF8(buffer, &name_utf8)) {
-        return -1;
-    }
-
-    strncpy(name, name_utf8.c_str(), len);
-    name[len - 1] = '\0';
-    return 0;
-}
-
-int adb_getlogin_r(char* buf, size_t bufsize) {
-    wchar_t buffer[UNLEN + 1];
-    DWORD len = sizeof(buffer);
-    if (!GetUserNameW(buffer, &len)) {
-        return -1;
-    }
-
-    std::string login;
-    if (!android::base::WideToUTF8(buffer, &login)) {
-        return -1;
-    }
-
-    strncpy(buf, login.c_str(), bufsize);
-    buf[bufsize - 1] = '\0';
-    return 0;
-}
-
 #undef accept
 int adb_socket_accept(borrowed_fd serverfd, struct sockaddr* addr, socklen_t* addrlen) {
     FH serverfh = _fh_from_int(serverfd, __func__);
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 2a1ca11..7af99c9 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -174,12 +174,8 @@
 }
 
 static void dump_thread_info(log_t* log, const ThreadInfo& thread_info) {
-  // Deny logd, logd.reader, logd.writer, logd.auditd, logd.control ...
-  // TODO: Why is this controlled by thread name?
-  if (thread_info.thread_name == "logd" ||
-      android::base::StartsWith(thread_info.thread_name, "logd.")) {
-    log->should_retrieve_logcat = false;
-  }
+  // Don't try to collect logs from the threads that implement the logging system itself.
+  if (thread_info.uid == AID_LOGD) log->should_retrieve_logcat = false;
 
   _LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s  >>> %s <<<\n", thread_info.pid,
        thread_info.tid, thread_info.thread_name.c_str(), thread_info.process_name.c_str());
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index bdb786c..6673543 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -271,6 +271,7 @@
     required: [
         "mke2fs",
         "make_f2fs",
+        "make_f2fs_casefold",
     ],
     dist: {
         targets: [
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index fd009e7..0e918a3 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -21,6 +21,7 @@
 my_dist_files := $(SOONG_HOST_OUT_EXECUTABLES)/mke2fs
 my_dist_files += $(SOONG_HOST_OUT_EXECUTABLES)/e2fsdroid
 my_dist_files += $(SOONG_HOST_OUT_EXECUTABLES)/make_f2fs
+my_dist_files += $(SOONG_HOST_OUT_EXECUTABLES)/make_f2fs_casefold
 my_dist_files += $(SOONG_HOST_OUT_EXECUTABLES)/sload_f2fs
 $(call dist-for-goals,dist_files sdk win_sdk,$(my_dist_files))
 my_dist_files :=
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 88bb234..9f22be5 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -301,13 +301,10 @@
     return true;
 }
 
-static bool needs_block_encryption(const FstabEntry& entry);
-static bool should_use_metadata_encryption(const FstabEntry& entry);
-
 // Read the primary superblock from an ext4 filesystem.  On failure return
 // false.  If it's not an ext4 filesystem, also set FS_STAT_INVALID_MAGIC.
-static bool read_ext4_superblock(const std::string& blk_device, const FstabEntry& entry,
-                                 struct ext4_super_block* sb, int* fs_stat) {
+static bool read_ext4_superblock(const std::string& blk_device, struct ext4_super_block* sb,
+                                 int* fs_stat) {
     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(blk_device.c_str(), O_RDONLY | O_CLOEXEC)));
 
     if (fd < 0) {
@@ -324,29 +321,7 @@
         LINFO << "Invalid ext4 superblock on '" << blk_device << "'";
         // not a valid fs, tune2fs, fsck, and mount  will all fail.
         *fs_stat |= FS_STAT_INVALID_MAGIC;
-
-        bool encrypted = should_use_metadata_encryption(entry) || needs_block_encryption(entry);
-        if (entry.mount_point == "/data" &&
-            (!encrypted || android::base::StartsWith(blk_device, "/dev/block/dm-"))) {
-            // try backup superblock, if main superblock is corrupted
-            for (unsigned int blocksize = EXT4_MIN_BLOCK_SIZE; blocksize <= EXT4_MAX_BLOCK_SIZE;
-                 blocksize *= 2) {
-                uint64_t superblock = blocksize * 8;
-                if (blocksize == EXT4_MIN_BLOCK_SIZE) superblock++;
-
-                if (TEMP_FAILURE_RETRY(pread(fd, sb, sizeof(*sb), superblock * blocksize)) !=
-                    sizeof(*sb)) {
-                    PERROR << "Can't read '" << blk_device << "' superblock";
-                    return false;
-                }
-                if (is_ext4_superblock_valid(sb) &&
-                    (1 << (10 + sb->s_log_block_size) == blocksize)) {
-                    *fs_stat &= ~FS_STAT_INVALID_MAGIC;
-                    break;
-                }
-            }
-        }
-        if (*fs_stat & FS_STAT_INVALID_MAGIC) return false;
+        return false;
     }
     *fs_stat |= FS_STAT_IS_EXT4;
     LINFO << "superblock s_max_mnt_count:" << sb->s_max_mnt_count << "," << blk_device;
@@ -687,7 +662,7 @@
     if (is_extfs(entry.fs_type)) {
         struct ext4_super_block sb;
 
-        if (read_ext4_superblock(blk_device, entry, &sb, &fs_stat)) {
+        if (read_ext4_superblock(blk_device, &sb, &fs_stat)) {
             if ((sb.s_feature_incompat & EXT4_FEATURE_INCOMPAT_RECOVER) != 0 ||
                 (sb.s_state & EXT4_VALID_FS) == 0) {
                 LINFO << "Filesystem on " << blk_device << " was not cleanly shutdown; "
@@ -717,7 +692,7 @@
          entry.fs_mgr_flags.fs_verity || entry.fs_mgr_flags.ext_meta_csum)) {
         struct ext4_super_block sb;
 
-        if (read_ext4_superblock(blk_device, entry, &sb, &fs_stat)) {
+        if (read_ext4_superblock(blk_device, &sb, &fs_stat)) {
             tune_reserved_size(blk_device, entry, &sb, &fs_stat);
             tune_encrypt(blk_device, entry, &sb, &fs_stat);
             tune_verity(blk_device, entry, &sb, &fs_stat);
diff --git a/init/AndroidTest.xml b/init/AndroidTest.xml
index 17f509a..6f22ab7 100644
--- a/init/AndroidTest.xml
+++ b/init/AndroidTest.xml
@@ -32,4 +32,7 @@
         <option name="module-name" value="CtsInitTestCases" />
         <option name="runtime-hint" value="65s" />
     </test>
+    <!-- Controller that will skip the module if a native bridge situation is detected -->
+    <!-- For example: module wants to run arm32 and device is x86 -->
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.NativeBridgeModuleController" />
 </configuration>
diff --git a/init/capabilities.cpp b/init/capabilities.cpp
index a91cd1d..0b9f161 100644
--- a/init/capabilities.cpp
+++ b/init/capabilities.cpp
@@ -28,47 +28,55 @@
 namespace init {
 
 static const std::map<std::string, int> cap_map = {
-    CAP_MAP_ENTRY(CHOWN),
-    CAP_MAP_ENTRY(DAC_OVERRIDE),
-    CAP_MAP_ENTRY(DAC_READ_SEARCH),
-    CAP_MAP_ENTRY(FOWNER),
-    CAP_MAP_ENTRY(FSETID),
-    CAP_MAP_ENTRY(KILL),
-    CAP_MAP_ENTRY(SETGID),
-    CAP_MAP_ENTRY(SETUID),
-    CAP_MAP_ENTRY(SETPCAP),
-    CAP_MAP_ENTRY(LINUX_IMMUTABLE),
-    CAP_MAP_ENTRY(NET_BIND_SERVICE),
-    CAP_MAP_ENTRY(NET_BROADCAST),
-    CAP_MAP_ENTRY(NET_ADMIN),
-    CAP_MAP_ENTRY(NET_RAW),
-    CAP_MAP_ENTRY(IPC_LOCK),
-    CAP_MAP_ENTRY(IPC_OWNER),
-    CAP_MAP_ENTRY(SYS_MODULE),
-    CAP_MAP_ENTRY(SYS_RAWIO),
-    CAP_MAP_ENTRY(SYS_CHROOT),
-    CAP_MAP_ENTRY(SYS_PTRACE),
-    CAP_MAP_ENTRY(SYS_PACCT),
-    CAP_MAP_ENTRY(SYS_ADMIN),
-    CAP_MAP_ENTRY(SYS_BOOT),
-    CAP_MAP_ENTRY(SYS_NICE),
-    CAP_MAP_ENTRY(SYS_RESOURCE),
-    CAP_MAP_ENTRY(SYS_TIME),
-    CAP_MAP_ENTRY(SYS_TTY_CONFIG),
-    CAP_MAP_ENTRY(MKNOD),
-    CAP_MAP_ENTRY(LEASE),
-    CAP_MAP_ENTRY(AUDIT_WRITE),
-    CAP_MAP_ENTRY(AUDIT_CONTROL),
-    CAP_MAP_ENTRY(SETFCAP),
-    CAP_MAP_ENTRY(MAC_OVERRIDE),
-    CAP_MAP_ENTRY(MAC_ADMIN),
-    CAP_MAP_ENTRY(SYSLOG),
-    CAP_MAP_ENTRY(WAKE_ALARM),
-    CAP_MAP_ENTRY(BLOCK_SUSPEND),
-    CAP_MAP_ENTRY(AUDIT_READ),
+        CAP_MAP_ENTRY(CHOWN),
+        CAP_MAP_ENTRY(DAC_OVERRIDE),
+        CAP_MAP_ENTRY(DAC_READ_SEARCH),
+        CAP_MAP_ENTRY(FOWNER),
+        CAP_MAP_ENTRY(FSETID),
+        CAP_MAP_ENTRY(KILL),
+        CAP_MAP_ENTRY(SETGID),
+        CAP_MAP_ENTRY(SETUID),
+        CAP_MAP_ENTRY(SETPCAP),
+        CAP_MAP_ENTRY(LINUX_IMMUTABLE),
+        CAP_MAP_ENTRY(NET_BIND_SERVICE),
+        CAP_MAP_ENTRY(NET_BROADCAST),
+        CAP_MAP_ENTRY(NET_ADMIN),
+        CAP_MAP_ENTRY(NET_RAW),
+        CAP_MAP_ENTRY(IPC_LOCK),
+        CAP_MAP_ENTRY(IPC_OWNER),
+        CAP_MAP_ENTRY(SYS_MODULE),
+        CAP_MAP_ENTRY(SYS_RAWIO),
+        CAP_MAP_ENTRY(SYS_CHROOT),
+        CAP_MAP_ENTRY(SYS_PTRACE),
+        CAP_MAP_ENTRY(SYS_PACCT),
+        CAP_MAP_ENTRY(SYS_ADMIN),
+        CAP_MAP_ENTRY(SYS_BOOT),
+        CAP_MAP_ENTRY(SYS_NICE),
+        CAP_MAP_ENTRY(SYS_RESOURCE),
+        CAP_MAP_ENTRY(SYS_TIME),
+        CAP_MAP_ENTRY(SYS_TTY_CONFIG),
+        CAP_MAP_ENTRY(MKNOD),
+        CAP_MAP_ENTRY(LEASE),
+        CAP_MAP_ENTRY(AUDIT_WRITE),
+        CAP_MAP_ENTRY(AUDIT_CONTROL),
+        CAP_MAP_ENTRY(SETFCAP),
+        CAP_MAP_ENTRY(MAC_OVERRIDE),
+        CAP_MAP_ENTRY(MAC_ADMIN),
+        CAP_MAP_ENTRY(SYSLOG),
+        CAP_MAP_ENTRY(WAKE_ALARM),
+        CAP_MAP_ENTRY(BLOCK_SUSPEND),
+        CAP_MAP_ENTRY(AUDIT_READ),
+#if defined(__BIONIC__)
+        CAP_MAP_ENTRY(PERFMON),
+        CAP_MAP_ENTRY(BPF),
+#endif
 };
 
+#if defined(__BIONIC__)
+static_assert(CAP_LAST_CAP == CAP_BPF, "CAP_LAST_CAP is not CAP_BPF");
+#else
 static_assert(CAP_LAST_CAP == CAP_AUDIT_READ, "CAP_LAST_CAP is not CAP_AUDIT_READ");
+#endif
 
 static bool ComputeCapAmbientSupported() {
 #if defined(__ANDROID__)
diff --git a/init/perfboot.py b/init/perfboot.py
index 713290b..4b23ad2 100755
--- a/init/perfboot.py
+++ b/init/perfboot.py
@@ -349,9 +349,9 @@
     # Filter out invalid data.
     end_times = [get_last_value(record, end_tag) for record in record_list
                  if get_last_value(record, end_tag) != 0]
-    print 'mean: ', mean(end_times)
-    print 'median:', median(end_times)
-    print 'standard deviation:', stddev(end_times)
+    print 'mean:', int(round(mean(end_times))), 'ms'
+    print 'median:', int(round(median(end_times))), 'ms'
+    print 'standard deviation:', int(round(stddev(end_times))), 'ms'
 
 
 def do_iteration(device, interval_adjuster, event_tags_re, end_tag):
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 6051ac7..3a91969 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -17,6 +17,7 @@
 liblog_sources = [
     "log_event_list.cpp",
     "log_event_write.cpp",
+    "log_size.cpp",
     "logger_name.cpp",
     "logger_read.cpp",
     "logger_write.cpp",
diff --git a/liblog/include/log/log_read.h b/liblog/include/log/log_read.h
index 23d76f4..1736934 100644
--- a/liblog/include/log/log_read.h
+++ b/liblog/include/log/log_read.h
@@ -81,10 +81,17 @@
 
 log_id_t android_logger_get_id(struct logger* logger);
 
+/* Clears the given log buffer. */
 int android_logger_clear(struct logger* logger);
+/* Return the allotted size for the given log buffer. */
 long android_logger_get_log_size(struct logger* logger);
+/* Set the allotted size for the given log buffer. */
 int android_logger_set_log_size(struct logger* logger, unsigned long size);
+/* Return the actual, uncompressed size that can be read from the given log buffer. */
 long android_logger_get_log_readable_size(struct logger* logger);
+/* Return the actual, compressed size that the given log buffer is consuming. */
+long android_logger_get_log_consumed_size(struct logger* logger);
+/* Deprecated.  Always returns '4' regardless of input. */
 int android_logger_get_log_version(struct logger* logger);
 
 struct logger_list;
diff --git a/liblog/log_size.cpp b/liblog/log_size.cpp
new file mode 100644
index 0000000..7f13c8c
--- /dev/null
+++ b/liblog/log_size.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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 <private/android_logger.h>
+
+#include <array>
+#include <optional>
+#include <string>
+
+#include <android-base/parseint.h>
+
+#ifdef __ANDROID__
+#include <sys/system_properties.h>
+#endif
+
+bool __android_logger_valid_buffer_size(unsigned long value) {
+  return LOG_BUFFER_MIN_SIZE <= value && value <= LOG_BUFFER_MAX_SIZE;
+}
+
+#ifdef __ANDROID__
+
+static std::optional<unsigned long> GetBufferSizeProperty(const std::string& key) {
+  char value[PROP_VALUE_MAX] = {};
+  if (__system_property_get(key.c_str(), value) <= 0) {
+    return {};
+  }
+
+  uint32_t size;
+  if (!android::base::ParseByteCount(value, &size)) {
+    return {};
+  }
+
+  if (!__android_logger_valid_buffer_size(size)) {
+    return {};
+  }
+
+  return size;
+}
+
+unsigned long __android_logger_get_buffer_size(log_id_t log_id) {
+  std::string buffer_name = android_log_id_to_name(log_id);
+  std::array<std::string, 4> properties = {
+      "persist.logd.size." + buffer_name,
+      "ro.logd.size." + buffer_name,
+      "persist.logd.size",
+      "ro.logd.size",
+  };
+
+  for (const auto& property : properties) {
+    if (auto size = GetBufferSizeProperty(property)) {
+      return *size;
+    }
+  }
+
+  char value[PROP_VALUE_MAX] = {};
+  if (__system_property_get("ro.config.low_ram", value) > 0 && !strcmp(value, "true")) {
+    return LOG_BUFFER_MIN_SIZE;
+  }
+
+  return LOG_BUFFER_SIZE;
+}
+
+#else
+
+// Default to 1MB for host.
+unsigned long __android_logger_get_buffer_size(log_id_t) {
+  return 1024 * 1024;
+}
+
+#endif
\ No newline at end of file
diff --git a/liblog/logd_reader.cpp b/liblog/logd_reader.cpp
index 82ed6b2..611caed 100644
--- a/liblog/logd_reader.cpp
+++ b/liblog/logd_reader.cpp
@@ -35,13 +35,14 @@
 
 #include <string>
 
+#include <android-base/parseint.h>
 #include <private/android_logger.h>
 
 #include "logger.h"
 
 // Connects to /dev/socket/<name> and returns the associated fd or returns -1 on error.
 // O_CLOEXEC is always set.
-static int socket_local_client(const std::string& name, int type) {
+static int socket_local_client(const std::string& name, int type, bool timeout) {
   sockaddr_un addr = {.sun_family = AF_LOCAL};
 
   std::string path = "/dev/socket/" + name;
@@ -55,6 +56,18 @@
     return -1;
   }
 
+  if (timeout) {
+    // Sending and receiving messages should be instantaneous, but we don't want to wait forever if
+    // logd is hung, so we set a gracious 2s timeout.
+    struct timeval t = {2, 0};
+    if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &t, sizeof(t)) == -1) {
+      return -1;
+    }
+    if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t)) == -1) {
+      return -1;
+    }
+  }
+
   if (connect(fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) {
     close(fd);
     return -1;
@@ -69,7 +82,7 @@
   size_t len;
   char* cp;
   int errno_save = 0;
-  int sock = socket_local_client("logd", SOCK_STREAM);
+  int sock = socket_local_client("logd", SOCK_STREAM, true);
   if (sock < 0) {
     return sock;
   }
@@ -148,26 +161,56 @@
   return check_log_success(buf, SendLogdControlMessage(buf, sizeof(buf)));
 }
 
-/* returns the total size of the log's ring buffer */
-long android_logger_get_log_size(struct logger* logger) {
+enum class LogSizeType : uint32_t {
+  kAllotted = 0,
+  kReadable,
+  kConsumed,
+};
+
+static long GetLogSize(struct logger* logger, LogSizeType type) {
   if (!android_logger_is_logd(logger)) {
     return -EINVAL;
   }
 
   uint32_t log_id = android_logger_get_id(logger);
   char buf[512];
-  snprintf(buf, sizeof(buf), "getLogSize %" PRIu32, log_id);
+  switch (type) {
+    case LogSizeType::kAllotted:
+      snprintf(buf, sizeof(buf), "getLogSize %" PRIu32, log_id);
+      break;
+    case LogSizeType::kReadable:
+      snprintf(buf, sizeof(buf), "getLogSizeReadable %" PRIu32, log_id);
+      break;
+    case LogSizeType::kConsumed:
+      snprintf(buf, sizeof(buf), "getLogSizeUsed %" PRIu32, log_id);
+      break;
+    default:
+      abort();
+  }
 
   ssize_t ret = SendLogdControlMessage(buf, sizeof(buf));
   if (ret < 0) {
     return ret;
   }
 
-  if ((buf[0] < '0') || ('9' < buf[0])) {
+  long size;
+  if (!android::base::ParseInt(buf, &size)) {
     return -1;
   }
 
-  return atol(buf);
+  return size;
+}
+
+long android_logger_get_log_size(struct logger* logger) {
+  return GetLogSize(logger, LogSizeType::kAllotted);
+}
+
+long android_logger_get_log_readable_size(struct logger* logger) {
+  return GetLogSize(logger, LogSizeType::kReadable);
+}
+
+long android_logger_get_log_consumed_size(struct logger* logger) {
+  return GetLogSize(logger, LogSizeType::kConsumed);
 }
 
 int android_logger_set_log_size(struct logger* logger, unsigned long size) {
@@ -182,31 +225,6 @@
   return check_log_success(buf, SendLogdControlMessage(buf, sizeof(buf)));
 }
 
-/*
- * returns the readable size of the log's ring buffer (that is, amount of the
- * log consumed)
- */
-long android_logger_get_log_readable_size(struct logger* logger) {
-  if (!android_logger_is_logd(logger)) {
-    return -EINVAL;
-  }
-
-  uint32_t log_id = android_logger_get_id(logger);
-  char buf[512];
-  snprintf(buf, sizeof(buf), "getLogSizeUsed %" PRIu32, log_id);
-
-  ssize_t ret = SendLogdControlMessage(buf, sizeof(buf));
-  if (ret < 0) {
-    return ret;
-  }
-
-  if ((buf[0] < '0') || ('9' < buf[0])) {
-    return -1;
-  }
-
-  return atol(buf);
-}
-
 int android_logger_get_log_version(struct logger*) {
   return 4;
 }
@@ -268,7 +286,7 @@
     return sock;
   }
 
-  sock = socket_local_client("logdr", SOCK_SEQPACKET);
+  sock = socket_local_client("logdr", SOCK_SEQPACKET, false);
   if (sock <= 0) {
     if ((sock == -1) && errno) {
       return -errno;
diff --git a/liblog/properties.cpp b/liblog/properties.cpp
index 9990137..88f0bf1 100644
--- a/liblog/properties.cpp
+++ b/liblog/properties.cpp
@@ -364,153 +364,6 @@
   return do_cache2_char(&security);
 }
 
-/*
- * Interface that represents the logd buffer size determination so that others
- * need not guess our intentions.
- */
-
-/* cache structure */
-struct cache_property {
-  struct cache cache;
-  char property[PROP_VALUE_MAX];
-};
-
-static void refresh_cache_property(struct cache_property* cache, const char* key) {
-  if (!cache->cache.pinfo) {
-    cache->cache.pinfo = __system_property_find(key);
-    if (!cache->cache.pinfo) {
-      return;
-    }
-  }
-  cache->cache.serial = __system_property_serial(cache->cache.pinfo);
-  __system_property_read(cache->cache.pinfo, 0, cache->property);
-}
-
-bool __android_logger_valid_buffer_size(unsigned long value) {
-  return LOG_BUFFER_MIN_SIZE <= value && value <= LOG_BUFFER_MAX_SIZE;
-}
-
-struct cache2_property_size {
-  pthread_mutex_t lock;
-  uint32_t serial;
-  const char* key_persist;
-  struct cache_property cache_persist;
-  const char* key_ro;
-  struct cache_property cache_ro;
-  unsigned long (*const evaluate)(const struct cache2_property_size* self);
-};
-
-static inline unsigned long do_cache2_property_size(struct cache2_property_size* self) {
-  uint32_t current_serial;
-  int change_detected;
-  unsigned long v;
-
-  if (pthread_mutex_trylock(&self->lock)) {
-    /* We are willing to accept some race in this context */
-    return self->evaluate(self);
-  }
-
-  change_detected = check_cache(&self->cache_persist.cache) || check_cache(&self->cache_ro.cache);
-  current_serial = __system_property_area_serial();
-  if (current_serial != self->serial) {
-    change_detected = 1;
-  }
-  if (change_detected) {
-    refresh_cache_property(&self->cache_persist, self->key_persist);
-    refresh_cache_property(&self->cache_ro, self->key_ro);
-    self->serial = current_serial;
-  }
-  v = self->evaluate(self);
-
-  pthread_mutex_unlock(&self->lock);
-
-  return v;
-}
-
-static unsigned long property_get_size_from_cache(const struct cache_property* cache) {
-  char* cp;
-  unsigned long value = strtoul(cache->property, &cp, 10);
-
-  switch (*cp) {
-    case 'm':
-    case 'M':
-      value *= 1024;
-      [[fallthrough]];
-    case 'k':
-    case 'K':
-      value *= 1024;
-      [[fallthrough]];
-    case '\0':
-      break;
-
-    default:
-      value = 0;
-  }
-
-  if (!__android_logger_valid_buffer_size(value)) {
-    value = 0;
-  }
-
-  return value;
-}
-
-static unsigned long evaluate_property_get_size(const struct cache2_property_size* self) {
-  unsigned long size = property_get_size_from_cache(&self->cache_persist);
-  if (size) {
-    return size;
-  }
-  return property_get_size_from_cache(&self->cache_ro);
-}
-
-unsigned long __android_logger_get_buffer_size(log_id_t logId) {
-  static const char global_tunable[] = "persist.logd.size"; /* Settings App */
-  static const char global_default[] = "ro.logd.size";      /* BoardConfig.mk */
-  static struct cache2_property_size global = {
-      /* clang-format off */
-    PTHREAD_MUTEX_INITIALIZER, 0,
-    global_tunable, { { NULL, 0xFFFFFFFF }, {} },
-    global_default, { { NULL, 0xFFFFFFFF }, {} },
-    evaluate_property_get_size
-      /* clang-format on */
-  };
-  char key_persist[strlen(global_tunable) + strlen(".security") + 1];
-  char key_ro[strlen(global_default) + strlen(".security") + 1];
-  struct cache2_property_size local = {
-      /* clang-format off */
-    PTHREAD_MUTEX_INITIALIZER, 0,
-    key_persist, { { NULL, 0xFFFFFFFF }, {} },
-    key_ro,      { { NULL, 0xFFFFFFFF }, {} },
-    evaluate_property_get_size
-      /* clang-format on */
-  };
-  unsigned long property_size, default_size;
-
-  default_size = do_cache2_property_size(&global);
-  if (!default_size) {
-    char value[PROP_VALUE_MAX] = {};
-    if (__system_property_get("ro.config.low_ram", value) == 0 || strcmp(value, "true") != 0) {
-      default_size = LOG_BUFFER_SIZE;
-    } else {
-      default_size = LOG_BUFFER_MIN_SIZE;
-    }
-  }
-
-  snprintf(key_persist, sizeof(key_persist), "%s.%s", global_tunable,
-           android_log_id_to_name(logId));
-  snprintf(key_ro, sizeof(key_ro), "%s.%s", global_default, android_log_id_to_name(logId));
-  property_size = do_cache2_property_size(&local);
-
-  if (!property_size) {
-    property_size = default_size;
-  }
-
-  if (!property_size) {
-    property_size = LOG_BUFFER_SIZE;
-  }
-
-  return property_size;
-}
-
 #else
 
 int __android_log_is_loggable(int prio, const char*, int) {
diff --git a/liblog/tests/liblog_global_state.cpp b/liblog/tests/liblog_global_state.cpp
index 3508818..1d7ff9f 100644
--- a/liblog/tests/liblog_global_state.cpp
+++ b/liblog/tests/liblog_global_state.cpp
@@ -153,56 +153,65 @@
   message_seen = false;
 }
 
+static std::string UniqueLogTag() {
+  std::string tag = LOG_TAG;
+  tag += "-" + std::to_string(getpid());
+  return tag;
+}
+
 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));
+  auto tag = UniqueLogTag();
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), 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));
+  auto tag = UniqueLogTag();
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), 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(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), 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(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), 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(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), 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));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
 }
 
 TEST(liblog_global_state, is_loggable_tag_log_priority_only) {
 #ifdef __ANDROID__
-  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 tag = UniqueLogTag();
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), 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));
+  auto log_tag_property = std::string("log.tag.") + tag;
+  ASSERT_TRUE(android::base::SetProperty(log_tag_property, "d"));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), 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));
+  ASSERT_TRUE(android::base::SetProperty(log_tag_property, "w"));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
 
-  android::base::SetProperty(log_tag_property, "");
+  ASSERT_TRUE(android::base::SetProperty(log_tag_property, ""));
 #else
   GTEST_SKIP() << "No log tag properties on host";
 #endif
@@ -210,39 +219,40 @@
 
 TEST(liblog_global_state, is_loggable_both_set) {
 #ifdef __ANDROID__
-  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 tag = UniqueLogTag();
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), 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");
+  auto log_tag_property = std::string("log.tag.") + tag;
+  ASSERT_TRUE(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));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), 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));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), 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));
+  ASSERT_TRUE(android::base::SetProperty(log_tag_property, "d"));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), 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));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
 
-  android::base::SetProperty(log_tag_property, "");
+  ASSERT_TRUE(android::base::SetProperty(log_tag_property, ""));
 #else
   GTEST_SKIP() << "No log tag properties on host";
 #endif
diff --git a/libmodprobe/libmodprobe.cpp b/libmodprobe/libmodprobe.cpp
index bbdd317..ceabf62 100644
--- a/libmodprobe/libmodprobe.cpp
+++ b/libmodprobe/libmodprobe.cpp
@@ -336,7 +336,6 @@
     }
 
     ParseKernelCmdlineOptions();
-    android::base::SetMinimumLogSeverity(android::base::INFO);
 }
 
 void Modprobe::EnableBlocklist(bool enable) {
diff --git a/libunwindstack/tests/fuzz/UnwinderComponentCreator.cpp b/libunwindstack/tests/fuzz/UnwinderComponentCreator.cpp
index 94f5a73..0415ef6 100644
--- a/libunwindstack/tests/fuzz/UnwinderComponentCreator.cpp
+++ b/libunwindstack/tests/fuzz/UnwinderComponentCreator.cpp
@@ -16,6 +16,11 @@
 
 #include "UnwinderComponentCreator.h"
 
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
 std::unique_ptr<Regs> GetRegisters(ArchEnum arch) {
   switch (arch) {
     case unwindstack::ARCH_ARM: {
@@ -109,13 +114,28 @@
   return elf;
 }
 
+static constexpr size_t kPageSize = 4096;
+
+static constexpr uint64_t AlignToPage(uint64_t address) {
+  return (address + kPageSize - 1) & ~(kPageSize - 1);
+}
+
 std::unique_ptr<Maps> GetMaps(FuzzedDataProvider* data_provider) {
   std::unique_ptr<Maps> maps = std::make_unique<Maps>();
+  std::map<uint64_t, uint64_t> map_ends;
   uint8_t entry_count = data_provider->ConsumeIntegralInRange<uint8_t>(0, kMaxMapEntryCount);
   for (uint8_t i = 0; i < entry_count; i++) {
-    uint64_t start = data_provider->ConsumeIntegral<uint64_t>();
-    uint64_t end = data_provider->ConsumeIntegralInRange<uint64_t>(start, UINT64_MAX);
-    uint64_t offset = data_provider->ConsumeIntegral<uint64_t>();
+    uint64_t start = AlignToPage(data_provider->ConsumeIntegral<uint64_t>());
+    uint64_t end = AlignToPage(data_provider->ConsumeIntegralInRange<uint64_t>(start, UINT64_MAX));
+    // Make sure not to add overlapping maps, that is not something that can
+    // happen in the real world.
+    auto entry = map_ends.upper_bound(start);
+    if (entry != map_ends.end() && end > entry->second) {
+      continue;
+    }
+    map_ends[end] = start;
+
+    uint64_t offset = AlignToPage(data_provider->ConsumeIntegral<uint64_t>());
     std::string map_info_name = data_provider->ConsumeRandomLengthString(kMaxMapInfoNameLen);
     uint8_t flags = PROT_READ | PROT_WRITE;
 
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index c7d1634..6b7e016 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -64,6 +64,7 @@
 using android::base::ParseUint;
 using android::base::Split;
 using android::base::StringPrintf;
+using android::base::WriteFully;
 
 class Logcat {
   public:
@@ -864,8 +865,7 @@
 
                     if (consolePipe) {
                         // need the trailing '\0'
-                        if (!android::base::WriteFully(fd, pipePurpose.c_str(),
-                                                       pipePurpose.size() + 1)) {
+                        if (!WriteFully(fd, pipePurpose.c_str(), pipePurpose.size() + 1)) {
                             close(fd);
                             return EXIT_FAILURE;
                         }
@@ -1064,19 +1064,23 @@
         if (getLogSize) {
             long size = android_logger_get_log_size(logger);
             long readable = android_logger_get_log_readable_size(logger);
+            long consumed = android_logger_get_log_consumed_size(logger);
 
             if (size < 0 || readable < 0) {
                 ReportErrorName(buffer_name, security_buffer_selected, &get_size_failures);
             } else {
                 auto size_format = format_of_size(size);
                 auto readable_format = format_of_size(readable);
+                auto consumed_format = format_of_size(consumed);
                 std::string str = android::base::StringPrintf(
-                        "%s: ring buffer is %lu %sB (%lu %sB consumed),"
+                        "%s: ring buffer is %lu %sB (%lu %sB consumed, %lu %sB readable),"
                         " max entry is %d B, max payload is %d B\n",
-                        buffer_name, size_format.first, size_format.second, readable_format.first,
-                        readable_format.second, (int)LOGGER_ENTRY_MAX_LEN,
-                        (int)LOGGER_ENTRY_MAX_PAYLOAD);
-                TEMP_FAILURE_RETRY(write(output_fd_.get(), str.data(), str.length()));
+                        buffer_name, size_format.first, size_format.second, consumed_format.first,
+                        consumed_format.second, readable_format.first, readable_format.second,
+                        (int)LOGGER_ENTRY_MAX_LEN, (int)LOGGER_ENTRY_MAX_PAYLOAD);
+                if (!WriteFully(output_fd_, str.data(), str.length())) {
+                    error(EXIT_FAILURE, errno, "Failed to write to output fd");
+                }
             }
         }
     }
@@ -1146,7 +1150,9 @@
         if (*cp == '\n') ++cp;
 
         size_t len = strlen(cp);
-        TEMP_FAILURE_RETRY(write(output_fd_.get(), cp, len));
+        if (!WriteFully(output_fd_, cp, len)) {
+            error(EXIT_FAILURE, errno, "Failed to write to output fd");
+        }
         return EXIT_SUCCESS;
     }
 
@@ -1190,7 +1196,9 @@
         PrintDividers(log_msg.id(), printDividers);
 
         if (print_binary_) {
-            TEMP_FAILURE_RETRY(write(output_fd_.get(), &log_msg, log_msg.len()));
+            if (!WriteFully(output_fd_, &log_msg, log_msg.len())) {
+                error(EXIT_FAILURE, errno, "Failed to write to output fd");
+            }
         } else {
             ProcessBuffer(&log_msg);
         }
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 2eeb0d9..6381ffa 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -46,6 +46,7 @@
     registerCmd(new ClearCmd(this));
     registerCmd(new GetBufSizeCmd(this));
     registerCmd(new SetBufSizeCmd(this));
+    registerCmd(new GetBufSizeReadableCmd(this));
     registerCmd(new GetBufSizeUsedCmd(this));
     registerCmd(new GetStatisticsCmd(this));
     registerCmd(new SetPruneListCmd(this));
@@ -136,6 +137,26 @@
     return 0;
 }
 
+int CommandListener::GetBufSizeReadableCmd::runCommand(SocketClient* cli, int argc, char** argv) {
+    setname();
+    if (argc < 2) {
+        cli->sendMsg("Missing Argument");
+        return 0;
+    }
+
+    int id = atoi(argv[1]);
+    if (id < LOG_ID_MIN || LOG_ID_MAX <= id) {
+        cli->sendMsg("Range Error");
+        return 0;
+    }
+
+    unsigned long size = stats()->SizeReadable((log_id_t)id);
+    char buf[512];
+    snprintf(buf, sizeof(buf), "%lu", size);
+    cli->sendMsg(buf);
+    return 0;
+}
+
 int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient* cli, int argc,
                                                    char** argv) {
     setname();
diff --git a/logd/CommandListener.h b/logd/CommandListener.h
index c3080ab..8e12634 100644
--- a/logd/CommandListener.h
+++ b/logd/CommandListener.h
@@ -57,6 +57,7 @@
     LogCmd(Clear, clear);
     LogCmd(GetBufSize, getLogSize);
     LogCmd(SetBufSize, setLogSize);
+    LogCmd(GetBufSizeReadable, getLogSizeReadable);
     LogCmd(GetBufSizeUsed, getLogSizeUsed);
     LogCmd(GetStatistics, getStatistics);
     LogCmd(GetPruneList, getPruneList);
diff --git a/logd/LogBufferTest.cpp b/logd/LogBufferTest.cpp
index 47d2a2f..1911105 100644
--- a/logd/LogBufferTest.cpp
+++ b/logd/LogBufferTest.cpp
@@ -34,16 +34,6 @@
 using android::base::Split;
 using android::base::StringPrintf;
 
-#ifndef __ANDROID__
-unsigned long __android_logger_get_buffer_size(log_id_t) {
-    return 1024 * 1024;
-}
-
-bool __android_logger_valid_buffer_size(unsigned long) {
-    return true;
-}
-#endif
-
 char* android::uidToName(uid_t) {
     return nullptr;
 }
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index e222d3f..faf9283 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -544,7 +544,7 @@
     bool ShouldPrune(log_id id, unsigned long max_size, unsigned long* prune_rows) const
             EXCLUDES(lock_);
 
-    // Snapshot of the sizes for a given log buffer.
+    // Return the consumed size of the given buffer.
     size_t Sizes(log_id_t id) const EXCLUDES(lock_) {
         auto lock = std::lock_guard{lock_};
         if (overhead_[id]) {
@@ -552,6 +552,13 @@
         }
         return mSizes[id];
     }
+
+    // Return the uncompressed size of the contents of the given buffer.
+    size_t SizeReadable(log_id_t id) const EXCLUDES(lock_) {
+        auto lock = std::lock_guard{lock_};
+        return mSizes[id];
+    }
+
     // TODO: Get rid of this entirely.
     static size_t sizesTotal() {
         return SizesTotal;
diff --git a/logd/ReplayMessages.cpp b/logd/ReplayMessages.cpp
index 5429233..56509ec 100644
--- a/logd/ReplayMessages.cpp
+++ b/logd/ReplayMessages.cpp
@@ -40,17 +40,6 @@
 using android::base::ParseUint;
 using android::base::Split;
 
-#ifndef __ANDROID__
-// This is hard coded to 1MB on host.  On device use persist.logd.size to configure.
-unsigned long __android_logger_get_buffer_size(log_id_t) {
-    return 1 * 1024 * 1024;
-}
-
-bool __android_logger_valid_buffer_size(unsigned long) {
-    return true;
-}
-#endif
-
 char* android::uidToName(uid_t) {
     return nullptr;
 }
diff --git a/logd/fuzz/log_buffer_log_fuzzer.cpp b/logd/fuzz/log_buffer_log_fuzzer.cpp
index 8309f95..d71a2f9 100644
--- a/logd/fuzz/log_buffer_log_fuzzer.cpp
+++ b/logd/fuzz/log_buffer_log_fuzzer.cpp
@@ -30,16 +30,6 @@
 #define MIN_TAG_ID 1000
 #define TAG_MOD 10
 
-#ifndef __ANDROID__
-unsigned long __android_logger_get_buffer_size(log_id_t) {
-    return 1024 * 1024;
-}
-
-bool __android_logger_valid_buffer_size(unsigned long) {
-    return true;
-}
-#endif
-
 char* android::uidToName(uid_t) {
     return strdup("fake");
 }
diff --git a/trusty/libtrusty/include/trusty/ipc.h b/trusty/libtrusty/include/trusty/ipc.h
new file mode 100644
index 0000000..1fa6fe4
--- /dev/null
+++ b/trusty/libtrusty/include/trusty/ipc.h
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#ifndef _UAPI_LINUX_TRUSTY_IPC_H_
+#define _UAPI_LINUX_TRUSTY_IPC_H_
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+#include <linux/uio.h>
+
+/**
+ * enum transfer_kind - How to send an fd to Trusty
+ * @TRUSTY_SHARE: Memory will be accessible by Linux and Trusty. On ARM it will
+ *                be mapped as nonsecure. Suitable for shared memory. The paired
+ *                fd must be a "memfd".
+ * @TRUSTY_LEND:  Memory will be accessible only to Trusty. On ARM it will be
+ *                transitioned to "Secure" memory if Trusty is in TrustZone.
+ *                This transfer kind is suitable for donating video buffers or
+ *                other similar resources. The paired fd may need to come from a
+ *                platform-specific allocator for memory that may be
+ *                transitioned to "Secure".
+ *
+ * Describes how the user would like the resource in question to be sent to
+ * Trusty. Options may be valid only for certain kinds of fds.
+ */
+enum transfer_kind {
+    TRUSTY_SHARE = 0,
+    TRUSTY_LEND = 1,
+};
+
+/**
+ * struct trusty_shm - Describes a transfer of memory to Trusty
+ * @fd:       The fd to transfer
+ * @transfer: How to transfer it - see &enum transfer_kind
+ */
+struct trusty_shm {
+    __s32 fd;
+    __u32 transfer;
+};
+
+/**
+ * struct tipc_send_msg_req - Request struct for @TIPC_IOC_SEND_MSG
+ * @iov:     Pointer to an array of &struct iovec describing data to be sent
+ * @shm:     Pointer to an array of &struct trusty_shm describing any file
+ *           descriptors to be transferred.
+ * @iov_cnt: Number of elements in the @iov array
+ * @shm_cnt: Number of elements in the @shm array
+ */
+struct tipc_send_msg_req {
+    __u64 iov;
+    __u64 shm;
+    __u64 iov_cnt;
+    __u64 shm_cnt;
+};
+
+#define TIPC_IOC_MAGIC 'r'
+#define TIPC_IOC_CONNECT _IOW(TIPC_IOC_MAGIC, 0x80, char*)
+#define TIPC_IOC_SEND_MSG _IOW(TIPC_IOC_MAGIC, 0x81, struct tipc_send_msg_req)
+
+#if defined(CONFIG_COMPAT)
+#define TIPC_IOC_CONNECT_COMPAT _IOW(TIPC_IOC_MAGIC, 0x80, compat_uptr_t)
+#endif
+
+#endif
diff --git a/trusty/libtrusty/include/trusty/tipc.h b/trusty/libtrusty/include/trusty/tipc.h
index a3f2a3f..b44afd3 100644
--- a/trusty/libtrusty/include/trusty/tipc.h
+++ b/trusty/libtrusty/include/trusty/tipc.h
@@ -21,7 +21,11 @@
 extern "C" {
 #endif
 
+#include <sys/uio.h>
+#include <trusty/ipc.h>
+
 int tipc_connect(const char *dev_name, const char *srv_name);
+ssize_t tipc_send(int fd, const struct iovec* iov, int iovcnt, struct trusty_shm* shm, int shmcnt);
 int tipc_close(int fd);
 
 #ifdef __cplusplus
diff --git a/trusty/libtrusty/tipc-test/tipc_test.c b/trusty/libtrusty/tipc-test/tipc_test.c
index d20d4ee..ca581dc 100644
--- a/trusty/libtrusty/tipc-test/tipc_test.c
+++ b/trusty/libtrusty/tipc-test/tipc_test.c
@@ -21,6 +21,8 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <getopt.h>
+#define __USE_GNU
+#include <sys/mman.h>
 #include <sys/uio.h>
 
 #include <trusty/tipc.h>
@@ -39,6 +41,7 @@
 static const char *closer2_name = "com.android.ipc-unittest.srv.closer2";
 static const char *closer3_name = "com.android.ipc-unittest.srv.closer3";
 static const char *main_ctrl_name = "com.android.ipc-unittest.ctrl";
+static const char* receiver_name = "com.android.trusty.memref.receiver";
 
 static const char *_sopts = "hsvD:t:r:m:b:";
 static const struct option _lopts[] =  {
@@ -66,25 +69,25 @@
 "\n"
 ;
 
-static const char *usage_long =
-"\n"
-"The following tests are available:\n"
-"   connect      - connect to datasink service\n"
-"   connect_foo  - connect to non existing service\n"
-"   burst_write  - send messages to datasink service\n"
-"   echo         - send/receive messages to echo service\n"
-"   select       - test select call\n"
-"   blocked_read - test blocked read\n"
-"   closer1      - connection closed by remote (test1)\n"
-"   closer2      - connection closed by remote (test2)\n"
-"   closer3      - connection closed by remote (test3)\n"
-"   ta2ta-ipc    - execute TA to TA unittest\n"
-"   dev-uuid     - print device uuid\n"
-"   ta-access    - test ta-access flags\n"
-"   writev       - writev test\n"
-"   readv        - readv test\n"
-"\n"
-;
+static const char* usage_long =
+        "\n"
+        "The following tests are available:\n"
+        "   connect      - connect to datasink service\n"
+        "   connect_foo  - connect to non existing service\n"
+        "   burst_write  - send messages to datasink service\n"
+        "   echo         - send/receive messages to echo service\n"
+        "   select       - test select call\n"
+        "   blocked_read - test blocked read\n"
+        "   closer1      - connection closed by remote (test1)\n"
+        "   closer2      - connection closed by remote (test2)\n"
+        "   closer3      - connection closed by remote (test3)\n"
+        "   ta2ta-ipc    - execute TA to TA unittest\n"
+        "   dev-uuid     - print device uuid\n"
+        "   ta-access    - test ta-access flags\n"
+        "   writev       - writev test\n"
+        "   readv        - readv test\n"
+        "   send-fd      - transmit memfd to trusty, use as shm\n"
+        "\n";
 
 static uint opt_repeat  = 1;
 static uint opt_msgsize = 32;
@@ -885,6 +888,66 @@
 	return 0;
 }
 
+static int send_fd_test(void) {
+    int ret;
+    int memfd = -1;
+    int fd = -1;
+    volatile char* buf = MAP_FAILED;
+
+    fd = tipc_connect(dev_name, receiver_name);
+    if (fd < 0) {
+        fprintf(stderr, "Failed to connect to test support TA - is it missing?\n");
+        ret = -1;
+        goto cleanup;
+    }
+
+    memfd = memfd_create("tipc-send-fd", 0);
+    if (memfd < 0) {
+        fprintf(stderr, "Failed to create memfd: %s\n", strerror(errno));
+        ret = -1;
+        goto cleanup;
+    }
+
+    if (ftruncate(memfd, PAGE_SIZE) < 0) {
+        fprintf(stderr, "Failed to resize memfd: %s\n", strerror(errno));
+        ret = -1;
+        goto cleanup;
+    }
+
+    buf = mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, memfd, 0);
+    if (buf == MAP_FAILED) {
+        fprintf(stderr, "Failed to map memfd: %s\n", strerror(errno));
+        ret = -1;
+        goto cleanup;
+    }
+
+    strcpy((char*)buf, "From NS");
+
+    struct trusty_shm shm = {
+            .fd = memfd,
+            .transfer = TRUSTY_SHARE,
+    };
+
+    ssize_t rc = tipc_send(fd, NULL, 0, &shm, 1);
+    if (rc < 0) {
+        fprintf(stderr, "tipc_send failed\n");
+        ret = rc;
+        goto cleanup;
+    }
+    char c;
+    read(fd, &c, 1);
+    tipc_close(fd);
+
+    ret = strcmp("Hello from Trusty!", (const char*)buf) ? (-1) : 0;
+
+cleanup:
+    if (buf != MAP_FAILED) {
+        munmap((char*)buf, PAGE_SIZE);
+    }
+    close(memfd);
+    tipc_close(fd);
+    return ret;
+}
 
 int main(int argc, char **argv)
 {
@@ -933,10 +996,12 @@
 		rc = writev_test(opt_repeat, opt_msgsize, opt_variable);
 	} else if (strcmp(test_name, "readv") == 0) {
 		rc = readv_test(opt_repeat, opt_msgsize, opt_variable);
-	} else {
-		fprintf(stderr, "Unrecognized test name '%s'\n", test_name);
-		print_usage_and_exit(argv[0], EXIT_FAILURE, true);
-	}
+    } else if (strcmp(test_name, "send-fd") == 0) {
+        rc = send_fd_test();
+    } else {
+        fprintf(stderr, "Unrecognized test name '%s'\n", test_name);
+        print_usage_and_exit(argv[0], EXIT_FAILURE, true);
+    }
 
-	return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+    return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/trusty/libtrusty/tipc_ioctl.h b/trusty/libtrusty/tipc_ioctl.h
deleted file mode 100644
index 27da56a..0000000
--- a/trusty/libtrusty/tipc_ioctl.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _TIPC_IOCTL_H
-#define _TIPC_IOCTL_H
-
-#include <linux/ioctl.h>
-#include <linux/types.h>
-
-#define TIPC_IOC_MAGIC			'r'
-#define TIPC_IOC_CONNECT		_IOW(TIPC_IOC_MAGIC, 0x80, char *)
-
-#endif
diff --git a/trusty/libtrusty/trusty.c b/trusty/libtrusty/trusty.c
index a6238af..ad4d8cd 100644
--- a/trusty/libtrusty/trusty.c
+++ b/trusty/libtrusty/trusty.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -27,7 +27,7 @@
 
 #include <log/log.h>
 
-#include "tipc_ioctl.h"
+#include <trusty/ipc.h>
 
 int tipc_connect(const char *dev_name, const char *srv_name)
 {
@@ -55,6 +55,22 @@
 	return fd;
 }
 
+ssize_t tipc_send(int fd, const struct iovec* iov, int iovcnt, struct trusty_shm* shms,
+                  int shmcnt) {
+    struct tipc_send_msg_req req;
+    req.iov = (__u64)iov;
+    req.iov_cnt = (__u64)iovcnt;
+    req.shm = (__u64)shms;
+    req.shm_cnt = (__u64)shmcnt;
+
+    int rc = ioctl(fd, TIPC_IOC_SEND_MSG, &req);
+    if (rc < 0) {
+        ALOGE("%s: failed to send message (err=%d)\n", __func__, rc);
+    }
+
+    return rc;
+}
+
 void tipc_close(int fd)
 {
 	close(fd);