Snap for 5307677 from 8e8ec5cf2147be7b89231f07040225ef20f15edf to qt-release

Change-Id: Ia8d4757f1967107c4126849d803e4857af4b1b16
diff --git a/fs_mgr/libfs_avb/Android.bp b/fs_mgr/libfs_avb/Android.bp
index 3e93265..a3c76ab 100644
--- a/fs_mgr/libfs_avb/Android.bp
+++ b/fs_mgr/libfs_avb/Android.bp
@@ -24,6 +24,8 @@
         "avb_ops.cpp",
         "avb_util.cpp",
         "fs_avb.cpp",
+        "fs_avb_util.cpp",
+        "types.cpp",
         "util.cpp",
     ],
     static_libs: [
@@ -98,6 +100,7 @@
     srcs: [
         "tests/basic_test.cpp",
         "tests/fs_avb_test.cpp",
+        "tests/fs_avb_util_test.cpp",
     ],
 }
 
@@ -115,3 +118,26 @@
         "tests/util_test.cpp",
     ],
 }
+
+cc_test {
+    name: "libfs_avb_device_test",
+    test_suites: ["device-tests"],
+    static_libs: [
+        "libavb",
+        "libdm",
+        "libfs_avb",
+        "libfstab",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcrypto",
+    ],
+    srcs: [
+        "tests/fs_avb_device_test.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+}
diff --git a/fs_mgr/libfs_avb/avb_ops.h b/fs_mgr/libfs_avb/avb_ops.h
index c0f12aa..a849d94 100644
--- a/fs_mgr/libfs_avb/avb_ops.h
+++ b/fs_mgr/libfs_avb/avb_ops.h
@@ -27,7 +27,7 @@
 #include <string>
 #include <vector>
 
-#include <fs_avb/fs_avb.h>
+#include <fs_avb/types.h>
 #include <libavb/libavb.h>
 
 namespace android {
diff --git a/fs_mgr/libfs_avb/avb_util.cpp b/fs_mgr/libfs_avb/avb_util.cpp
index 08f87b4..fa9080e 100644
--- a/fs_mgr/libfs_avb/avb_util.cpp
+++ b/fs_mgr/libfs_avb/avb_util.cpp
@@ -34,56 +34,11 @@
 namespace android {
 namespace fs_mgr {
 
-// Helper functions to print enum class VBMetaVerifyResult.
-const char* VBMetaVerifyResultToString(VBMetaVerifyResult result) {
-    // clang-format off
-    static const char* const name[] = {
-        "ResultSuccess",
-        "ResultError",
-        "ResultErrorVerification",
-        "ResultUnknown",
-    };
-    // clang-format on
-
-    uint32_t index = static_cast<uint32_t>(result);
-    uint32_t unknown_index = sizeof(name) / sizeof(char*) - 1;
-    if (index >= unknown_index) {
-        index = unknown_index;
-    }
-
-    return name[index];
-}
-
-std::ostream& operator<<(std::ostream& os, VBMetaVerifyResult result) {
-    os << VBMetaVerifyResultToString(result);
-    return os;
-}
-
-// class VBMetaData
-// ----------------
-std::unique_ptr<AvbVBMetaImageHeader> VBMetaData::GetVBMetaHeader(bool update_vbmeta_size) {
-    auto vbmeta_header = std::make_unique<AvbVBMetaImageHeader>();
-
-    if (!vbmeta_header) return nullptr;
-
-    /* Byteswap the header. */
-    avb_vbmeta_image_header_to_host_byte_order((AvbVBMetaImageHeader*)vbmeta_ptr_.get(),
-                                               vbmeta_header.get());
-    if (update_vbmeta_size) {
-        vbmeta_size_ = sizeof(AvbVBMetaImageHeader) +
-                       vbmeta_header->authentication_data_block_size +
-                       vbmeta_header->auxiliary_data_block_size;
-    }
-
-    return vbmeta_header;
-}
-
 // Constructs dm-verity arguments for sending DM_TABLE_LOAD ioctl to kernel.
 // See the following link for more details:
 // https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity
-bool ConstructVerityTable(const AvbHashtreeDescriptor& hashtree_desc, const std::string& salt,
-                          const std::string& root_digest, const std::string& blk_device,
-                          android::dm::DmTable* table) {
+bool ConstructVerityTable(const FsAvbHashtreeDescriptor& hashtree_desc,
+                          const std::string& blk_device, android::dm::DmTable* table) {
     // Loads androidboot.veritymode from kernel cmdline.
     std::string verity_mode;
     if (!fs_mgr_get_boot_config("veritymode", &verity_mode)) {
@@ -104,12 +59,12 @@
     std::ostringstream hash_algorithm;
     hash_algorithm << hashtree_desc.hash_algorithm;
 
-    android::dm::DmTargetVerity target(0, hashtree_desc.image_size / 512,
-                                       hashtree_desc.dm_verity_version, blk_device, blk_device,
-                                       hashtree_desc.data_block_size, hashtree_desc.hash_block_size,
-                                       hashtree_desc.image_size / hashtree_desc.data_block_size,
-                                       hashtree_desc.tree_offset / hashtree_desc.hash_block_size,
-                                       hash_algorithm.str(), root_digest, salt);
+    android::dm::DmTargetVerity target(
+            0, hashtree_desc.image_size / 512, hashtree_desc.dm_verity_version, blk_device,
+            blk_device, hashtree_desc.data_block_size, hashtree_desc.hash_block_size,
+            hashtree_desc.image_size / hashtree_desc.data_block_size,
+            hashtree_desc.tree_offset / hashtree_desc.hash_block_size, hash_algorithm.str(),
+            hashtree_desc.root_digest, hashtree_desc.salt);
     if (hashtree_desc.fec_size > 0) {
         target.UseFec(blk_device, hashtree_desc.fec_num_roots,
                       hashtree_desc.fec_offset / hashtree_desc.data_block_size,
@@ -126,12 +81,10 @@
     return table->AddTarget(std::make_unique<android::dm::DmTargetVerity>(target));
 }
 
-bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const AvbHashtreeDescriptor& hashtree_desc,
-                           const std::string& salt, const std::string& root_digest,
+bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const FsAvbHashtreeDescriptor& hashtree_desc,
                            bool wait_for_verity_dev) {
     android::dm::DmTable table;
-    if (!ConstructVerityTable(hashtree_desc, salt, root_digest, fstab_entry->blk_device, &table) ||
-        !table.valid()) {
+    if (!ConstructVerityTable(hashtree_desc, fstab_entry->blk_device, &table) || !table.valid()) {
         LERROR << "Failed to construct verity table.";
         return false;
     }
@@ -164,12 +117,11 @@
     return true;
 }
 
-std::unique_ptr<AvbHashtreeDescriptor> GetHashtreeDescriptor(
-    const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images,
-    std::string* out_salt, std::string* out_digest) {
+std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
+        const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images) {
     bool found = false;
     const uint8_t* desc_partition_name;
-    auto hashtree_desc = std::make_unique<AvbHashtreeDescriptor>();
+    auto hashtree_desc = std::make_unique<FsAvbHashtreeDescriptor>();
 
     for (const auto& vbmeta : vbmeta_images) {
         size_t num_descriptors;
@@ -209,15 +161,17 @@
     }
 
     if (!found) {
-        LERROR << "Partition descriptor not found: " << partition_name.c_str();
+        LERROR << "Hashtree descriptor not found: " << partition_name;
         return nullptr;
     }
 
+    hashtree_desc->partition_name = partition_name;
+
     const uint8_t* desc_salt = desc_partition_name + hashtree_desc->partition_name_len;
-    *out_salt = BytesToHex(desc_salt, hashtree_desc->salt_len);
+    hashtree_desc->salt = BytesToHex(desc_salt, hashtree_desc->salt_len);
 
     const uint8_t* desc_digest = desc_salt + hashtree_desc->salt_len;
-    *out_digest = BytesToHex(desc_digest, hashtree_desc->root_digest_len);
+    hashtree_desc->root_digest = BytesToHex(desc_digest, hashtree_desc->root_digest_len);
 
     return hashtree_desc;
 }
@@ -235,18 +189,15 @@
         return false;
     }
 
-    std::string salt;
-    std::string root_digest;
-    std::unique_ptr<AvbHashtreeDescriptor> hashtree_descriptor =
-        GetHashtreeDescriptor(partition_name, vbmeta_images, &salt, &root_digest);
+    std::unique_ptr<FsAvbHashtreeDescriptor> hashtree_descriptor =
+            GetHashtreeDescriptor(partition_name, vbmeta_images);
     if (!hashtree_descriptor) {
         return false;
     }
 
     // Converts HASHTREE descriptor to verity table to load into kernel.
     // When success, the new device path will be returned, e.g., /dev/block/dm-2.
-    return HashtreeDmVeritySetup(fstab_entry, *hashtree_descriptor, salt, root_digest,
-                                 wait_for_verity_dev);
+    return HashtreeDmVeritySetup(fstab_entry, *hashtree_descriptor, wait_for_verity_dev);
 }
 
 // Converts a AVB partition_name (without A/B suffix) to a device partition name.
@@ -420,6 +371,10 @@
     uint64_t vbmeta_size = VBMetaData::kMaxVBMetaSize;
     bool is_vbmeta_partition = StartsWith(partition_name, "vbmeta");
 
+    if (out_verify_result) {
+        *out_verify_result = VBMetaVerifyResult::kError;
+    }
+
     if (!is_vbmeta_partition) {
         std::unique_ptr<AvbFooter> footer = GetAvbFooter(fd);
         if (!footer) {
@@ -445,7 +400,10 @@
 
     auto verify_result =
             VerifyVBMetaSignature(*vbmeta, expected_public_key_blob, out_public_key_data);
-    if (out_verify_result != nullptr) *out_verify_result = verify_result;
+
+    if (out_verify_result != nullptr) {
+        *out_verify_result = verify_result;
+    }
 
     if (verify_result == VBMetaVerifyResult::kSuccess ||
         verify_result == VBMetaVerifyResult::kErrorVerification) {
@@ -508,6 +466,10 @@
         const std::string& expected_public_key_blob, bool allow_verification_error,
         bool rollback_protection, bool is_chained_vbmeta, std::string* out_public_key_data,
         bool* out_verification_disabled, VBMetaVerifyResult* out_verify_result) {
+    if (out_verify_result) {
+        *out_verify_result = VBMetaVerifyResult::kError;
+    }
+
     // Ensures the device path (might be a symlink created by init) is ready to access.
     if (!WaitForFile(image_path, 1s)) {
         PERROR << "No such path: " << image_path;
diff --git a/fs_mgr/libfs_avb/avb_util.h b/fs_mgr/libfs_avb/avb_util.h
index 4b54e27..9babd88 100644
--- a/fs_mgr/libfs_avb/avb_util.h
+++ b/fs_mgr/libfs_avb/avb_util.h
@@ -24,19 +24,11 @@
 #include <libavb/libavb.h>
 #include <libdm/dm.h>
 
-#include "fs_avb/fs_avb.h"
+#include "fs_avb/types.h"
 
 namespace android {
 namespace fs_mgr {
 
-enum class VBMetaVerifyResult {
-    kSuccess = 0,
-    kError = 1,
-    kErrorVerification = 2,
-};
-
-std::ostream& operator<<(std::ostream& os, VBMetaVerifyResult);
-
 struct ChainInfo {
     std::string partition_name;
     std::string public_key_blob;
@@ -46,16 +38,13 @@
 };
 
 // AvbHashtreeDescriptor to dm-verity table setup.
-std::unique_ptr<AvbHashtreeDescriptor> GetHashtreeDescriptor(
-    const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images,
-    std::string* out_salt, std::string* out_digest);
+std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
+        const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images);
 
-bool ConstructVerityTable(const AvbHashtreeDescriptor& hashtree_desc, const std::string& salt,
-                          const std::string& root_digest, const std::string& blk_device,
-                          android::dm::DmTable* table);
+bool ConstructVerityTable(const FsAvbHashtreeDescriptor& hashtree_desc,
+                          const std::string& blk_device, android::dm::DmTable* table);
 
-bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const AvbHashtreeDescriptor& hashtree_desc,
-                           const std::string& salt, const std::string& root_digest,
+bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const FsAvbHashtreeDescriptor& hashtree_desc,
                            bool wait_for_verity_dev);
 
 // Searches a Avb hashtree descriptor in vbmeta_images for fstab_entry, to enable dm-verity.
diff --git a/fs_mgr/libfs_avb/fs_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp
index 1af3b33..938e149 100644
--- a/fs_mgr/libfs_avb/fs_avb.cpp
+++ b/fs_mgr/libfs_avb/fs_avb.cpp
@@ -76,33 +76,6 @@
     return std::make_pair(digest, total_size);
 }
 
-// Helper functions to dump enum class AvbHandleStatus.
-const char* AvbHandleStatusToString(AvbHandleStatus status) {
-    // clang-format off
-    static const char* const name[] = {
-        "Success",
-        "Uninitialized",
-        "HashtreeDisabled",
-        "VerificationDisabled",
-        "VerificationError",
-        "Unknown",
-    };
-    // clang-format on
-
-    uint32_t index = static_cast<uint32_t>(status);
-    uint32_t unknown_index = sizeof(name) / sizeof(char*) - 1;
-    if (index >= unknown_index) {
-        index = unknown_index;
-    }
-
-    return name[index];
-}
-
-std::ostream& operator<<(std::ostream& os, AvbHandleStatus status) {
-    os << AvbHandleStatusToString(status);
-    return os;
-}
-
 // class AvbVerifier
 // -----------------
 // Reads the following values from kernel cmdline and provides the
diff --git a/fs_mgr/libfs_avb/fs_avb_util.cpp b/fs_mgr/libfs_avb/fs_avb_util.cpp
new file mode 100644
index 0000000..f82f83d
--- /dev/null
+++ b/fs_mgr/libfs_avb/fs_avb_util.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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 "fs_avb/fs_avb_util.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <android-base/strings.h>
+#include <fstab/fstab.h>
+#include <libavb/libavb.h>
+#include <libdm/dm.h>
+
+#include "avb_util.h"
+#include "util.h"
+
+namespace android {
+namespace fs_mgr {
+
+// Given a FstabEntry, loads and verifies the vbmeta, to extract the Avb Hashtree descriptor.
+std::unique_ptr<VBMetaData> LoadAndVerifyVbmeta(const FstabEntry& fstab_entry,
+                                                const std::string& expected_public_key_blob,
+                                                std::string* out_public_key_data,
+                                                std::string* out_avb_partition_name,
+                                                VBMetaVerifyResult* out_verify_result) {
+    // Derives partition_name from blk_device to query the corresponding AVB HASHTREE descriptor
+    // to setup dm-verity. The partition_names in AVB descriptors are without A/B suffix.
+    std::string avb_partition_name = DeriveAvbPartitionName(fstab_entry, fs_mgr_get_slot_suffix(),
+                                                            fs_mgr_get_other_slot_suffix());
+    if (out_avb_partition_name) {
+        *out_avb_partition_name = avb_partition_name;
+    }
+
+    // Updates fstab_entry->blk_device from <partition> to /dev/block/dm-<N> if
+    // it's a logical partition.
+    std::string device_path = fstab_entry.blk_device;
+    if (fstab_entry.fs_mgr_flags.logical &&
+        !android::base::StartsWith(fstab_entry.blk_device, "/")) {
+        dm::DeviceMapper& dm = dm::DeviceMapper::Instance();
+        if (!dm.GetDmDevicePathByName(fstab_entry.blk_device, &device_path)) {
+            LERROR << "Failed to resolve logical device path for: " << fstab_entry.blk_device;
+            return nullptr;
+        }
+    }
+
+    return LoadAndVerifyVbmetaByPath(device_path, avb_partition_name, expected_public_key_blob,
+                                     true /* allow_verification_error */,
+                                     false /* rollback_protection */, false /* is_chained_vbmeta */,
+                                     out_public_key_data, nullptr /* out_verification_disabled */,
+                                     out_verify_result);
+}
+
+// Given a path, loads and verifies the vbmeta, to extract the Avb Hashtree descriptor.
+std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
+        const std::string& avb_partition_name, VBMetaData&& vbmeta) {
+    if (!vbmeta.size()) return nullptr;
+
+    std::vector<VBMetaData> vbmeta_images;
+    vbmeta_images.emplace_back(std::move(vbmeta));
+    return GetHashtreeDescriptor(avb_partition_name, vbmeta_images);
+}
+
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
index d4e3a6e..d026722 100644
--- a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
@@ -21,32 +21,13 @@
 #include <string>
 #include <vector>
 
+#include <fs_avb/types.h>
 #include <fstab/fstab.h>
 #include <libavb/libavb.h>
 
 namespace android {
 namespace fs_mgr {
 
-enum class AvbHashtreeResult {
-    kSuccess = 0,
-    kFail,
-    kDisabled,
-};
-
-enum class HashAlgorithm {
-    kInvalid = 0,
-    kSHA256 = 1,
-    kSHA512 = 2,
-};
-
-enum class AvbHandleStatus {
-    kSuccess = 0,
-    kUninitialized = 1,
-    kHashtreeDisabled = 2,
-    kVerificationDisabled = 3,
-    kVerificationError = 4,
-};
-
 struct VBMetaInfo {
     std::string digest;
     HashAlgorithm hash_algorithm;
@@ -58,51 +39,6 @@
         : digest(std::move(digest_value)), hash_algorithm(algorithm), total_size(size) {}
 };
 
-class VBMetaData {
-  public:
-    // Constructors
-    VBMetaData() : vbmeta_ptr_(nullptr), vbmeta_size_(0){};
-
-    VBMetaData(const uint8_t* data, size_t size, const std::string& partition_name)
-        : vbmeta_ptr_(new (std::nothrow) uint8_t[size]),
-          vbmeta_size_(size),
-          partition_name_(partition_name) {
-        // The ownership of data is NOT transferred, i.e., the caller still
-        // needs to release the memory as we make a copy here.
-        memcpy(vbmeta_ptr_.get(), data, size * sizeof(uint8_t));
-    }
-
-    explicit VBMetaData(size_t size, const std::string& partition_name)
-        : vbmeta_ptr_(new (std::nothrow) uint8_t[size]),
-          vbmeta_size_(size),
-          partition_name_(partition_name) {}
-
-    // Extracts vbmeta header from the vbmeta buffer, set update_vbmeta_size to
-    // true to update vbmeta_size_ to the actual size with valid content.
-    std::unique_ptr<AvbVBMetaImageHeader> GetVBMetaHeader(bool update_vbmeta_size = false);
-
-    // Sets the vbmeta_path where we load the vbmeta data. Could be a partition or a file.
-    // e.g.,
-    // - /dev/block/by-name/system_a
-    // - /path/to/system_other.img.
-    void set_vbmeta_path(std::string vbmeta_path) { vbmeta_path_ = std::move(vbmeta_path); }
-
-    // Get methods for each data member.
-    const std::string& partition() const { return partition_name_; }
-    const std::string& vbmeta_path() const { return vbmeta_path_; }
-    uint8_t* data() const { return vbmeta_ptr_.get(); }
-    const size_t& size() const { return vbmeta_size_; }
-
-    // Maximum size of a vbmeta data - 64 KiB.
-    static const size_t kMaxVBMetaSize = 64 * 1024;
-
-  private:
-    std::unique_ptr<uint8_t[]> vbmeta_ptr_;
-    size_t vbmeta_size_;
-    std::string partition_name_;
-    std::string vbmeta_path_;
-};
-
 class FsManagerAvbOps;
 
 class AvbHandle;
diff --git a/fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h
new file mode 100644
index 0000000..ec8badb
--- /dev/null
+++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h
@@ -0,0 +1,40 @@
+/*
+ * 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 <string>
+
+#include <fs_avb/types.h>
+#include <fstab/fstab.h>
+#include <libavb/libavb.h>
+
+namespace android {
+namespace fs_mgr {
+
+// Given a FstabEntry, loads and verifies the vbmeta.
+std::unique_ptr<VBMetaData> LoadAndVerifyVbmeta(const FstabEntry& fstab_entry,
+                                                const std::string& expected_public_key_blob,
+                                                std::string* out_public_key_data,
+                                                std::string* out_avb_partition_name,
+                                                VBMetaVerifyResult* out_verify_result);
+
+// Gets the hashtree descriptor for avb_partition_name from the vbmeta.
+std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
+        const std::string& avb_partition_name, VBMetaData&& vbmeta);
+
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/fs_mgr/libfs_avb/include/fs_avb/types.h b/fs_mgr/libfs_avb/include/fs_avb/types.h
new file mode 100644
index 0000000..bd638e6
--- /dev/null
+++ b/fs_mgr/libfs_avb/include/fs_avb/types.h
@@ -0,0 +1,110 @@
+/*
+ * 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 <cstring>
+#include <memory>
+#include <ostream>
+
+#include <libavb/libavb.h>
+
+namespace android {
+namespace fs_mgr {
+
+enum class VBMetaVerifyResult {
+    kSuccess = 0,
+    kError = 1,
+    kErrorVerification = 2,
+};
+
+std::ostream& operator<<(std::ostream& os, VBMetaVerifyResult);
+
+enum class AvbHashtreeResult {
+    kSuccess = 0,
+    kFail,
+    kDisabled,
+};
+
+enum class HashAlgorithm {
+    kInvalid = 0,
+    kSHA256 = 1,
+    kSHA512 = 2,
+};
+
+enum class AvbHandleStatus {
+    kSuccess = 0,
+    kUninitialized = 1,
+    kHashtreeDisabled = 2,
+    kVerificationDisabled = 3,
+    kVerificationError = 4,
+};
+
+std::ostream& operator<<(std::ostream& os, AvbHandleStatus status);
+
+struct FsAvbHashtreeDescriptor : AvbHashtreeDescriptor {
+    std::string partition_name;
+    std::string salt;
+    std::string root_digest;
+};
+
+class VBMetaData {
+  public:
+    // Constructors
+    VBMetaData() : vbmeta_ptr_(nullptr), vbmeta_size_(0){};
+
+    VBMetaData(const uint8_t* data, size_t size, const std::string& partition_name)
+        : vbmeta_ptr_(new (std::nothrow) uint8_t[size]),
+          vbmeta_size_(size),
+          partition_name_(partition_name) {
+        // The ownership of data is NOT transferred, i.e., the caller still
+        // needs to release the memory as we make a copy here.
+        std::memcpy(vbmeta_ptr_.get(), data, size * sizeof(uint8_t));
+    }
+
+    explicit VBMetaData(size_t size, const std::string& partition_name)
+        : vbmeta_ptr_(new (std::nothrow) uint8_t[size]),
+          vbmeta_size_(size),
+          partition_name_(partition_name) {}
+
+    // Extracts vbmeta header from the vbmeta buffer, set update_vbmeta_size to
+    // true to update vbmeta_size_ to the actual size with valid content.
+    std::unique_ptr<AvbVBMetaImageHeader> GetVBMetaHeader(bool update_vbmeta_size = false);
+
+    // Sets the vbmeta_path where we load the vbmeta data. Could be a partition or a file.
+    // e.g.,
+    // - /dev/block/by-name/system_a
+    // - /path/to/system_other.img.
+    void set_vbmeta_path(std::string vbmeta_path) { vbmeta_path_ = std::move(vbmeta_path); }
+
+    // Get methods for each data member.
+    const std::string& partition() const { return partition_name_; }
+    const std::string& vbmeta_path() const { return vbmeta_path_; }
+    uint8_t* data() const { return vbmeta_ptr_.get(); }
+    const size_t& size() const { return vbmeta_size_; }
+
+    // Maximum size of a vbmeta data - 64 KiB.
+    static const size_t kMaxVBMetaSize = 64 * 1024;
+
+  private:
+    std::unique_ptr<uint8_t[]> vbmeta_ptr_;
+    size_t vbmeta_size_;
+    std::string partition_name_;
+    std::string vbmeta_path_;
+};
+
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/fs_mgr/libfs_avb/run_tests.sh b/fs_mgr/libfs_avb/run_tests.sh
new file mode 100755
index 0000000..5d2ce3d
--- /dev/null
+++ b/fs_mgr/libfs_avb/run_tests.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+#
+# Run host tests
+atest libfs_avb_test                 # Tests public libfs_avb APIs.
+atest libfs_avb_internal_test        # Tests libfs_avb private APIs.
+
+# Run device tests
+atest libfs_avb_device_test          # Test public libfs_avb APIs on a device.
diff --git a/fs_mgr/libfs_avb/tests/fs_avb_device_test.cpp b/fs_mgr/libfs_avb/tests/fs_avb_device_test.cpp
new file mode 100644
index 0000000..fc4eb5f
--- /dev/null
+++ b/fs_mgr/libfs_avb/tests/fs_avb_device_test.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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 <android-base/properties.h>
+#include <fs_avb/fs_avb_util.h>
+#include <fstab/fstab.h>
+#include <gtest/gtest.h>
+
+#include <sys/types.h>
+#include <unistd.h>
+
+using android::fs_mgr::Fstab;
+using android::fs_mgr::FstabEntry;
+using android::fs_mgr::VBMetaData;
+using android::fs_mgr::VBMetaVerifyResult;
+
+namespace fs_avb_device_test {
+
+// system vbmeta might not be at the end of /system when dynamic partition is
+// enabled. Therefore, disable it by default.
+TEST(PublicFsAvbDeviceTest, DISABLED_LoadAndVerifyVbmeta_SystemVbmeta) {
+    Fstab fstab;
+    EXPECT_TRUE(ReadDefaultFstab(&fstab));
+
+    FstabEntry* system_entry = GetEntryForMountPoint(&fstab, "/system");
+    EXPECT_NE(nullptr, system_entry);
+
+    std::string out_public_key_data;
+    std::string out_avb_partition_name;
+    VBMetaVerifyResult out_verify_result;
+    std::unique_ptr<VBMetaData> vbmeta =
+            LoadAndVerifyVbmeta(*system_entry, "" /* expected_public_key_blob */,
+                                &out_public_key_data, &out_avb_partition_name, &out_verify_result);
+
+    EXPECT_NE(nullptr, vbmeta);
+    EXPECT_EQ(VBMetaVerifyResult::kSuccess, out_verify_result);
+    EXPECT_EQ("system", out_avb_partition_name);
+    EXPECT_NE("", out_public_key_data);
+}
+
+TEST(PublicFsAvbDeviceTest, GetHashtreeDescriptor_SystemOther) {
+    // Non-A/B device doesn't have system_other partition.
+    if (fs_mgr_get_slot_suffix() == "") return;
+
+    // Skip running this test if system_other is a logical partition.
+    // Note that system_other is still a physical partition on "retrofit" devices.
+    if (android::base::GetBoolProperty("ro.boot.dynamic_partitions", false) &&
+        !android::base::GetBoolProperty("ro.boot.dynamic_partitions_retrofit", false)) {
+        return;
+    }
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile("/system/etc/fstab.postinstall", &fstab));
+
+    // It should have two lines in the fstab, the first for logical system_other,
+    // the other for physical system_other.
+    EXPECT_EQ(2UL, fstab.size());
+
+    // Use the 2nd fstab entry, which is for physical system_other partition.
+    FstabEntry* system_other = &fstab[1];
+    EXPECT_NE(nullptr, system_other);
+
+    std::string out_public_key_data;
+    std::string out_avb_partition_name;
+    VBMetaVerifyResult out_verify_result;
+    std::unique_ptr<VBMetaData> system_other_vbmeta =
+            LoadAndVerifyVbmeta(*system_other, "" /* expected_public_key_blob */,
+                                &out_public_key_data, &out_avb_partition_name, &out_verify_result);
+
+    EXPECT_NE(nullptr, system_other_vbmeta);
+    EXPECT_EQ(VBMetaVerifyResult::kSuccess, out_verify_result);
+    EXPECT_EQ("system_other", out_avb_partition_name);
+    EXPECT_NE("", out_public_key_data);
+
+    auto hashtree_desc =
+            GetHashtreeDescriptor(out_avb_partition_name, std::move(*system_other_vbmeta));
+    EXPECT_NE(nullptr, hashtree_desc);
+}
+
+}  // namespace fs_avb_device_test
diff --git a/fs_mgr/libfs_avb/tests/fs_avb_test_util.h b/fs_mgr/libfs_avb/tests/fs_avb_test_util.h
index 2e46644..ab1980b 100644
--- a/fs_mgr/libfs_avb/tests/fs_avb_test_util.h
+++ b/fs_mgr/libfs_avb/tests/fs_avb_test_util.h
@@ -29,7 +29,7 @@
 #include <android-base/unique_fd.h>
 #include <base/files/file_path.h>
 #include <base/strings/stringprintf.h>
-#include <fs_avb/fs_avb.h>
+#include <fs_avb/types.h>
 #include <gtest/gtest.h>
 
 // Utility macro to run the command expressed by the printf()-style string
diff --git a/fs_mgr/libfs_avb/tests/fs_avb_util_test.cpp b/fs_mgr/libfs_avb/tests/fs_avb_util_test.cpp
new file mode 100644
index 0000000..7c34009
--- /dev/null
+++ b/fs_mgr/libfs_avb/tests/fs_avb_util_test.cpp
@@ -0,0 +1,120 @@
+/*
+ * 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 <fs_avb/fs_avb_util.h>
+
+#include "fs_avb_test_util.h"
+
+namespace fs_avb_host_test {
+
+class PublicFsAvbUtilTest : public BaseFsAvbTest {
+  public:
+    PublicFsAvbUtilTest(){};
+
+  protected:
+    ~PublicFsAvbUtilTest(){};
+};
+
+TEST_F(PublicFsAvbUtilTest, GetHashtreeDescriptor) {
+    // Generates a raw system_other.img, use a smaller size to speed-up unit test.
+    const size_t system_image_size = 10 * 1024 * 1024;
+    const size_t system_partition_size = 15 * 1024 * 1024;
+    base::FilePath system_path = GenerateImage("system.img", system_image_size);
+
+    // Adds AVB Hashtree Footer.
+    AddAvbFooter(system_path, "hashtree", "system", system_partition_size, "SHA512_RSA4096", 20,
+                 data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
+                 "--internal_release_string \"unit test\"");
+
+    auto system_vbmeta = ExtractAndLoadVBMetaData(system_path, "system-vbmeta.img");
+
+    auto hashtree_desc =
+            GetHashtreeDescriptor("system" /* avb_partition_name */, std::move(system_vbmeta));
+    EXPECT_NE(nullptr, hashtree_desc);
+
+    // Checks the returned hashtree_desc matches the following info returned by avbtool.
+    EXPECT_EQ(
+            "Footer version:           1.0\n"
+            "Image size:               15728640 bytes\n"
+            "Original image size:      10485760 bytes\n"
+            "VBMeta offset:            10661888\n"
+            "VBMeta size:              2112 bytes\n"
+            "--\n"
+            "Minimum libavb version:   1.0\n"
+            "Header Block:             256 bytes\n"
+            "Authentication Block:     576 bytes\n"
+            "Auxiliary Block:          1280 bytes\n"
+            "Algorithm:                SHA512_RSA4096\n"
+            "Rollback Index:           20\n"
+            "Flags:                    0\n"
+            "Release String:           'unit test'\n"
+            "Descriptors:\n"
+            "    Hashtree descriptor:\n"
+            "      Version of dm-verity:  1\n"
+            "      Image Size:            10485760 bytes\n"
+            "      Tree Offset:           10485760\n"
+            "      Tree Size:             86016 bytes\n"
+            "      Data Block Size:       4096 bytes\n"
+            "      Hash Block Size:       4096 bytes\n"
+            "      FEC num roots:         2\n"
+            "      FEC offset:            10571776\n"
+            "      FEC size:              90112 bytes\n"
+            "      Hash Algorithm:        sha1\n"
+            "      Partition Name:        system\n"
+            "      Salt:                  d00df00d\n"
+            "      Root Digest:           a3d5dd307341393d85de356c384ff543ec1ed81b\n"
+            "      Flags:                 0\n",
+            InfoImage(system_path));
+
+    EXPECT_EQ(1UL, hashtree_desc->dm_verity_version);
+    EXPECT_EQ(10485760UL, hashtree_desc->image_size);
+    EXPECT_EQ(10485760UL, hashtree_desc->tree_offset);
+    EXPECT_EQ(86016UL, hashtree_desc->tree_size);
+    EXPECT_EQ(4096UL, hashtree_desc->data_block_size);
+    EXPECT_EQ(4096UL, hashtree_desc->hash_block_size);
+    EXPECT_EQ(2UL, hashtree_desc->fec_num_roots);
+    EXPECT_EQ(10571776UL, hashtree_desc->fec_offset);
+    EXPECT_EQ(90112UL, hashtree_desc->fec_size);
+    EXPECT_EQ(std::string("sha1"),
+              std::string(reinterpret_cast<const char*>(hashtree_desc->hash_algorithm)));
+    EXPECT_EQ(std::string("system").length(), hashtree_desc->partition_name_len);
+    EXPECT_EQ(hashtree_desc->partition_name, "system");
+    EXPECT_EQ(hashtree_desc->salt, "d00df00d");
+    EXPECT_EQ(hashtree_desc->root_digest, "a3d5dd307341393d85de356c384ff543ec1ed81b");
+
+    // Checks it's null if partition name doesn't match.
+    EXPECT_EQ(nullptr, GetHashtreeDescriptor("system_not_exist" /* avb_partition_name */,
+                                             std::move(system_vbmeta)));
+}
+
+TEST_F(PublicFsAvbUtilTest, GetHashtreeDescriptor_NotFound) {
+    // Generates a raw boot.img
+    const size_t image_size = 5 * 1024 * 1024;
+    const size_t partition_size = 10 * 1024 * 1024;
+    base::FilePath boot_path = GenerateImage("boot.img", image_size);
+    // Appends AVB Hash Footer.
+    AddAvbFooter(boot_path, "hash", "boot", partition_size, "SHA256_RSA4096", 10,
+                 data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
+                 "--internal_release_string \"unit test\"");
+    // Extracts boot vbmeta from boot.img into boot-vbmeta.img.
+    auto boot_vbmeta = ExtractAndLoadVBMetaData(boot_path, "boot-vbmeta.img");
+
+    auto hashtree_desc =
+            GetHashtreeDescriptor("boot" /* avb_partition_name */, std::move(boot_vbmeta));
+    EXPECT_EQ(nullptr, hashtree_desc);
+}
+
+}  // namespace fs_avb_host_test
diff --git a/fs_mgr/libfs_avb/types.cpp b/fs_mgr/libfs_avb/types.cpp
new file mode 100644
index 0000000..3c277f3
--- /dev/null
+++ b/fs_mgr/libfs_avb/types.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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 "fs_avb/types.h"
+
+namespace android {
+namespace fs_mgr {
+
+// Helper functions to print enum class VBMetaVerifyResult.
+const char* VBMetaVerifyResultToString(VBMetaVerifyResult result) {
+    // clang-format off
+    static const char* const name[] = {
+        "ResultSuccess",
+        "ResultError",
+        "ResultErrorVerification",
+        "ResultUnknown",
+    };
+    // clang-format on
+
+    uint32_t index = static_cast<uint32_t>(result);
+    uint32_t unknown_index = sizeof(name) / sizeof(char*) - 1;
+    if (index >= unknown_index) {
+        index = unknown_index;
+    }
+
+    return name[index];
+}
+
+std::ostream& operator<<(std::ostream& os, VBMetaVerifyResult result) {
+    os << VBMetaVerifyResultToString(result);
+    return os;
+}
+
+// Helper functions to dump enum class AvbHandleStatus.
+const char* AvbHandleStatusToString(AvbHandleStatus status) {
+    // clang-format off
+    static const char* const name[] = {
+        "Success",
+        "Uninitialized",
+        "HashtreeDisabled",
+        "VerificationDisabled",
+        "VerificationError",
+        "Unknown",
+    };
+    // clang-format on
+
+    uint32_t index = static_cast<uint32_t>(status);
+    uint32_t unknown_index = sizeof(name) / sizeof(char*) - 1;
+    if (index >= unknown_index) {
+        index = unknown_index;
+    }
+
+    return name[index];
+}
+
+std::ostream& operator<<(std::ostream& os, AvbHandleStatus status) {
+    os << AvbHandleStatusToString(status);
+    return os;
+}
+
+// class VBMetaData
+// ----------------
+std::unique_ptr<AvbVBMetaImageHeader> VBMetaData::GetVBMetaHeader(bool update_vbmeta_size) {
+    auto vbmeta_header = std::make_unique<AvbVBMetaImageHeader>();
+
+    if (!vbmeta_header) return nullptr;
+
+    /* Byteswap the header. */
+    avb_vbmeta_image_header_to_host_byte_order((AvbVBMetaImageHeader*)vbmeta_ptr_.get(),
+                                               vbmeta_header.get());
+    if (update_vbmeta_size) {
+        vbmeta_size_ = sizeof(AvbVBMetaImageHeader) +
+                       vbmeta_header->authentication_data_block_size +
+                       vbmeta_header->auxiliary_data_block_size;
+    }
+
+    return vbmeta_header;
+}
+
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/liblog/logd_reader.cpp b/liblog/logd_reader.cpp
index 2f0af4a..b7ba782 100644
--- a/liblog/logd_reader.cpp
+++ b/liblog/logd_reader.cpp
@@ -100,148 +100,29 @@
   return -EBADF;
 }
 
-/* Private copy of ../libcutils/socket_local_client.c prevent library loops */
+// 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) {
+  sockaddr_un addr = {.sun_family = AF_LOCAL};
 
-#if defined(_WIN32)
-
-LIBLOG_WEAK int socket_local_client(const char* name, int namespaceId, int type) {
-  errno = ENOSYS;
-  return -ENOSYS;
-}
-
-#else /* !_WIN32 */
-
-#include <sys/select.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/un.h>
-
-/* Private copy of ../libcutils/socket_local.h prevent library loops */
-#define FILESYSTEM_SOCKET_PREFIX "/tmp/"
-#define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/"
-/* End of ../libcutils/socket_local.h */
-
-#define LISTEN_BACKLOG 4
-
-/* Documented in header file. */
-LIBLOG_WEAK int socket_make_sockaddr_un(const char* name, int namespaceId,
-                                        struct sockaddr_un* p_addr, socklen_t* alen) {
-  memset(p_addr, 0, sizeof(*p_addr));
-  size_t namelen;
-
-  switch (namespaceId) {
-    case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
-#if defined(__linux__)
-      namelen = strlen(name);
-
-      /* Test with length +1 for the *initial* '\0'. */
-      if ((namelen + 1) > sizeof(p_addr->sun_path)) {
-        goto error;
-      }
-
-      /*
-       * Note: The path in this case is *not* supposed to be
-       * '\0'-terminated. ("man 7 unix" for the gory details.)
-       */
-
-      p_addr->sun_path[0] = 0;
-      memcpy(p_addr->sun_path + 1, name, namelen);
-#else
-      /* this OS doesn't have the Linux abstract namespace */
-
-      namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
-      /* unix_path_max appears to be missing on linux */
-      if (namelen > sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - 1) {
-        goto error;
-      }
-
-      strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
-      strcat(p_addr->sun_path, name);
-#endif
-      break;
-
-    case ANDROID_SOCKET_NAMESPACE_RESERVED:
-      namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
-      /* unix_path_max appears to be missing on linux */
-      if (namelen > sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - 1) {
-        goto error;
-      }
-
-      strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);
-      strcat(p_addr->sun_path, name);
-      break;
-
-    case ANDROID_SOCKET_NAMESPACE_FILESYSTEM:
-      namelen = strlen(name);
-      /* unix_path_max appears to be missing on linux */
-      if (namelen > sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - 1) {
-        goto error;
-      }
-
-      strcpy(p_addr->sun_path, name);
-      break;
-
-    default:
-      /* invalid namespace id */
-      return -1;
+  std::string path = "/dev/socket/" + name;
+  if (path.size() + 1 > sizeof(addr.sun_path)) {
+    return -1;
   }
+  strlcpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path));
 
-  p_addr->sun_family = AF_LOCAL;
-  *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
-  return 0;
-error:
-  return -1;
-}
-
-/**
- * connect to peer named "name" on fd
- * returns same fd or -1 on error.
- * fd is not closed on error. that's your job.
- *
- * Used by AndroidSocketImpl
- */
-LIBLOG_WEAK int socket_local_client_connect(int fd, const char* name, int namespaceId,
-                                            int type __unused) {
-  struct sockaddr_un addr;
-  socklen_t alen;
-  int err;
-
-  err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
-
-  if (err < 0) {
-    goto error;
-  }
-
-  if (connect(fd, (struct sockaddr*)&addr, alen) < 0) {
-    goto error;
-  }
-
-  return fd;
-
-error:
-  return -1;
-}
-
-/**
- * connect to peer named "name"
- * returns fd or -1 on error
- */
-LIBLOG_WEAK int socket_local_client(const char* name, int namespaceId, int type) {
-  int s;
-
-  s = socket(AF_LOCAL, type, 0);
-  if (s < 0) return -1;
-
-  if (0 > socket_local_client_connect(s, name, namespaceId, type)) {
-    close(s);
+  int fd = socket(AF_LOCAL, type | SOCK_CLOEXEC, 0);
+  if (fd == 0) {
     return -1;
   }
 
-  return s;
-}
+  if (connect(fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) {
+    close(fd);
+    return -1;
+  }
 
-#endif /* !_WIN32 */
-/* End of ../libcutils/socket_local_client.c */
+  return fd;
+}
 
 /* worker for sending the command to the logger */
 static ssize_t send_log_msg(struct android_log_logger* logger, const char* msg, char* buf,
@@ -250,7 +131,7 @@
   size_t len;
   char* cp;
   int errno_save = 0;
-  int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
+  int sock = socket_local_client("logd", SOCK_STREAM);
   if (sock < 0) {
     return sock;
   }
@@ -460,10 +341,10 @@
     return sock;
   }
 
-  sock = socket_local_client("logdr", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET);
+  sock = socket_local_client("logdr", SOCK_SEQPACKET);
   if (sock == 0) {
     /* Guarantee not file descriptor zero */
-    int newsock = socket_local_client("logdr", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET);
+    int newsock = socket_local_client("logdr", SOCK_SEQPACKET);
     close(sock);
     sock = newsock;
   }
diff --git a/liblog/tests/Android.bp b/liblog/tests/Android.bp
index 4ab2acb..50755ce 100644
--- a/liblog/tests/Android.bp
+++ b/liblog/tests/Android.bp
@@ -31,6 +31,7 @@
     shared_libs: [
         "libm",
         "libbase",
+        "libcutils",
     ],
     static_libs: ["liblog"],
     srcs: ["liblog_benchmark.cpp"],
diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp
index 6d78ed6..3534eb8 100644
--- a/liblog/tests/libc_test.cpp
+++ b/liblog/tests/libc_test.cpp
@@ -23,7 +23,7 @@
 #ifdef __ANDROID__
 #ifndef NO_PSTORE
   FILE* fp;
-  ASSERT_TRUE(NULL != (fp = fopen("/dev/pmsg0", "a")));
+  ASSERT_TRUE(NULL != (fp = fopen("/dev/pmsg0", "ae")));
   static const char message[] = "libc.__pstore_append\n";
   ASSERT_EQ((size_t)1, fwrite(message, sizeof(message), 1, fp));
   int fflushReturn = fflush(fp);
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index c8ac321..7d11ccf 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -172,7 +172,7 @@
  * Measure the time it takes to submit the android logging data to pstore
  */
 static void BM_pmsg_short(benchmark::State& state) {
-  int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
+  int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
   if (pstore_fd < 0) {
     state.SkipWithError("/dev/pmsg0");
     return;
@@ -248,7 +248,7 @@
  * best case aligned single block.
  */
 static void BM_pmsg_short_aligned(benchmark::State& state) {
-  int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
+  int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
   if (pstore_fd < 0) {
     state.SkipWithError("/dev/pmsg0");
     return;
@@ -323,7 +323,7 @@
  * best case aligned single block.
  */
 static void BM_pmsg_short_unaligned1(benchmark::State& state) {
-  int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
+  int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
   if (pstore_fd < 0) {
     state.SkipWithError("/dev/pmsg0");
     return;
@@ -398,7 +398,7 @@
  * best case aligned single block.
  */
 static void BM_pmsg_long_aligned(benchmark::State& state) {
-  int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
+  int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
   if (pstore_fd < 0) {
     state.SkipWithError("/dev/pmsg0");
     return;
@@ -471,7 +471,7 @@
  * best case aligned single block.
  */
 static void BM_pmsg_long_unaligned1(benchmark::State& state) {
-  int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
+  int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
   if (pstore_fd < 0) {
     state.SkipWithError("/dev/pmsg0");
     return;
@@ -949,8 +949,8 @@
 
 // Must be functionally identical to liblog internal __send_log_msg.
 static void send_to_control(char* buf, size_t len) {
-  int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
-                                 SOCK_STREAM);
+  int sock =
+      socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM | SOCK_CLOEXEC);
   if (sock < 0) return;
   size_t writeLen = strlen(buf) + 1;
 
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 83f0fa9..1f87b3e 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -93,7 +93,7 @@
 static std::string popenToString(const std::string& command) {
   std::string ret;
 
-  FILE* fp = popen(command.c_str(), "r");
+  FILE* fp = popen(command.c_str(), "re");
   if (fp) {
     if (!android::base::ReadFdToString(fileno(fp), &ret)) ret = "";
     pclose(fp);
@@ -645,7 +645,7 @@
   char buffer[512];
   snprintf(buffer, sizeof(buffer), "/proc/%u/stat", pid);
 
-  FILE* fp = fopen(buffer, "r");
+  FILE* fp = fopen(buffer, "re");
   if (!fp) {
     return;
   }
diff --git a/liblog/tests/log_radio_test.cpp b/liblog/tests/log_radio_test.cpp
index f202c67..fa1255e 100644
--- a/liblog/tests/log_radio_test.cpp
+++ b/liblog/tests/log_radio_test.cpp
@@ -91,7 +91,7 @@
       "logcat -b radio --pid=%u -d -s"
       " TEST__RLOGV TEST__RLOGD TEST__RLOGI TEST__RLOGW TEST__RLOGE",
       (unsigned)getpid());
-  FILE* fp = popen(buf.c_str(), "r");
+  FILE* fp = popen(buf.c_str(), "re");
   int count = 0;
   int count_false = 0;
   if (fp) {
diff --git a/liblog/tests/log_system_test.cpp b/liblog/tests/log_system_test.cpp
index 0656c0b..13f026d 100644
--- a/liblog/tests/log_system_test.cpp
+++ b/liblog/tests/log_system_test.cpp
@@ -91,7 +91,7 @@
       "logcat -b system --pid=%u -d -s"
       " TEST__SLOGV TEST__SLOGD TEST__SLOGI TEST__SLOGW TEST__SLOGE",
       (unsigned)getpid());
-  FILE* fp = popen(buf.c_str(), "r");
+  FILE* fp = popen(buf.c_str(), "re");
   int count = 0;
   int count_false = 0;
   if (fp) {
diff --git a/libnativebridge/Android.bp b/libnativebridge/Android.bp
index c54570e..10d42e4 100644
--- a/libnativebridge/Android.bp
+++ b/libnativebridge/Android.bp
@@ -1,5 +1,18 @@
+cc_defaults {
+    name: "libnativebridge-defaults",
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+    cppflags: [
+        "-fvisibility=protected",
+    ],
+    header_libs: ["libnativebridge-headers"],
+    export_header_lib_headers: ["libnativebridge-headers"],
+}
+
 cc_library_headers {
-    name: "libnativebridge-dummy-headers",
+    name: "libnativebridge-headers",
 
     host_supported: true,
     export_include_dirs: ["include"],
@@ -7,6 +20,7 @@
 
 cc_library {
     name: "libnativebridge",
+    defaults: ["libnativebridge-defaults"],
 
     host_supported: true,
     srcs: ["native_bridge.cc"],
@@ -16,6 +30,8 @@
     shared_libs: [
         "liblog",
     ],
+    // TODO(jiyong): remove this line after aosp/885921 lands
+    export_include_dirs: ["include"],
 
     target: {
         android: {
@@ -30,16 +46,16 @@
         symbol_file: "libnativebridge.map.txt",
         versions: ["1"],
     },
+}
 
-    export_include_dirs: ["include"],
+// TODO(b/124250621): eliminate the need for this library
+cc_library {
+    name: "libnativebridge_lazy",
+    defaults: ["libnativebridge-defaults"],
 
-    cflags: [
-        "-Werror",
-        "-Wall",
-    ],
-    cppflags: [
-        "-fvisibility=protected",
-    ],
+    host_supported: false,
+    srcs: ["native_bridge_lazy.cc"],
+    required: ["libnativebridge"],
 }
 
 subdirs = ["tests"]
diff --git a/libnativebridge/native_bridge_lazy.cc b/libnativebridge/native_bridge_lazy.cc
new file mode 100644
index 0000000..94c8084
--- /dev/null
+++ b/libnativebridge/native_bridge_lazy.cc
@@ -0,0 +1,167 @@
+/*
+ * 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 "nativebridge/native_bridge.h"
+#define LOG_TAG "nativebridge"
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <string.h>
+
+#include <log/log.h>
+
+namespace android {
+
+namespace {
+
+void* GetLibHandle() {
+  static void* handle = dlopen("libnativebridge.so", RTLD_NOW);
+  LOG_FATAL_IF(handle == nullptr, "Failed to load libnativebridge.so: %s", dlerror());
+  return handle;
+}
+
+template <typename FuncPtr>
+FuncPtr GetFuncPtr(const char* function_name) {
+  auto f = reinterpret_cast<FuncPtr>(dlsym(GetLibHandle(), function_name));
+  LOG_FATAL_IF(f == nullptr, "Failed to get address of %s: %s", function_name, dlerror());
+  return f;
+}
+
+#define GET_FUNC_PTR(name) GetFuncPtr<decltype(&name)>(#name)
+
+}  // namespace
+
+bool LoadNativeBridge(const char* native_bridge_library_filename,
+                      const struct NativeBridgeRuntimeCallbacks* runtime_callbacks) {
+  static auto f = GET_FUNC_PTR(LoadNativeBridge);
+  return f(native_bridge_library_filename, runtime_callbacks);
+}
+
+bool NeedsNativeBridge(const char* instruction_set) {
+  static auto f = GET_FUNC_PTR(NeedsNativeBridge);
+  return f(instruction_set);
+}
+
+bool PreInitializeNativeBridge(const char* app_data_dir, const char* instruction_set) {
+  static auto f = GET_FUNC_PTR(PreInitializeNativeBridge);
+  return f(app_data_dir, instruction_set);
+}
+
+bool InitializeNativeBridge(JNIEnv* env, const char* instruction_set) {
+  static auto f = GET_FUNC_PTR(InitializeNativeBridge);
+  return f(env, instruction_set);
+}
+
+void UnloadNativeBridge() {
+  static auto f = GET_FUNC_PTR(UnloadNativeBridge);
+  return f();
+}
+
+bool NativeBridgeAvailable() {
+  static auto f = GET_FUNC_PTR(NativeBridgeAvailable);
+  return f();
+}
+
+bool NativeBridgeInitialized() {
+  static auto f = GET_FUNC_PTR(NativeBridgeInitialized);
+  return f();
+}
+
+void* NativeBridgeLoadLibrary(const char* libpath, int flag) {
+  static auto f = GET_FUNC_PTR(NativeBridgeLoadLibrary);
+  return f(libpath, flag);
+}
+
+void* NativeBridgeGetTrampoline(void* handle, const char* name, const char* shorty, uint32_t len) {
+  static auto f = GET_FUNC_PTR(NativeBridgeGetTrampoline);
+  return f(handle, name, shorty, len);
+}
+
+bool NativeBridgeIsSupported(const char* libpath) {
+  static auto f = GET_FUNC_PTR(NativeBridgeIsSupported);
+  return f(libpath);
+}
+
+uint32_t NativeBridgeGetVersion() {
+  static auto f = GET_FUNC_PTR(NativeBridgeGetVersion);
+  return f();
+}
+
+NativeBridgeSignalHandlerFn NativeBridgeGetSignalHandler(int signal) {
+  static auto f = GET_FUNC_PTR(NativeBridgeGetSignalHandler);
+  return f(signal);
+}
+
+bool NativeBridgeError() {
+  static auto f = GET_FUNC_PTR(NativeBridgeError);
+  return f();
+}
+
+bool NativeBridgeNameAcceptable(const char* native_bridge_library_filename) {
+  static auto f = GET_FUNC_PTR(NativeBridgeNameAcceptable);
+  return f(native_bridge_library_filename);
+}
+
+int NativeBridgeUnloadLibrary(void* handle) {
+  static auto f = GET_FUNC_PTR(NativeBridgeUnloadLibrary);
+  return f(handle);
+}
+
+const char* NativeBridgeGetError() {
+  static auto f = GET_FUNC_PTR(NativeBridgeGetError);
+  return f();
+}
+
+bool NativeBridgeIsPathSupported(const char* path) {
+  static auto f = GET_FUNC_PTR(NativeBridgeIsPathSupported);
+  return f(path);
+}
+
+bool NativeBridgeInitAnonymousNamespace(const char* public_ns_sonames,
+                                        const char* anon_ns_library_path) {
+  static auto f = GET_FUNC_PTR(NativeBridgeInitAnonymousNamespace);
+  return f(public_ns_sonames, anon_ns_library_path);
+}
+
+struct native_bridge_namespace_t* NativeBridgeCreateNamespace(
+    const char* name, const char* ld_library_path, const char* default_library_path, uint64_t type,
+    const char* permitted_when_isolated_path, struct native_bridge_namespace_t* parent_ns) {
+  static auto f = GET_FUNC_PTR(NativeBridgeCreateNamespace);
+  return f(name, ld_library_path, default_library_path, type, permitted_when_isolated_path,
+           parent_ns);
+}
+
+bool NativeBridgeLinkNamespaces(struct native_bridge_namespace_t* from,
+                                struct native_bridge_namespace_t* to,
+                                const char* shared_libs_sonames) {
+  static auto f = GET_FUNC_PTR(NativeBridgeLinkNamespaces);
+  return f(from, to, shared_libs_sonames);
+}
+
+void* NativeBridgeLoadLibraryExt(const char* libpath, int flag,
+                                 struct native_bridge_namespace_t* ns) {
+  static auto f = GET_FUNC_PTR(NativeBridgeLoadLibraryExt);
+  return f(libpath, flag, ns);
+}
+
+struct native_bridge_namespace_t* NativeBridgeGetVendorNamespace() {
+  static auto f = GET_FUNC_PTR(NativeBridgeGetVendorNamespace);
+  return f();
+}
+
+#undef GET_FUNC_PTR
+
+}  // namespace android
diff --git a/libnativebridge/tests/Android.bp b/libnativebridge/tests/Android.bp
index 744a4a8..2bb8467 100644
--- a/libnativebridge/tests/Android.bp
+++ b/libnativebridge/tests/Android.bp
@@ -23,7 +23,7 @@
         "-Wextra",
         "-Werror",
     ],
-    header_libs: ["libnativebridge-dummy-headers"],
+    header_libs: ["libnativebridge-headers"],
     cppflags: ["-fvisibility=protected"],
 }
 
@@ -46,9 +46,8 @@
 }
 
 // Build the unit tests.
-cc_test {
-    name: "libnativebridge-tests",
-    host_supported: true,
+cc_defaults {
+    name: "libnativebridge-tests-defaults",
     test_per_src: true,
 
     cflags: [
@@ -81,12 +80,24 @@
 
     shared_libs: [
         "liblog",
-        "libnativebridge",
         "libnativebridge-dummy",
     ],
     header_libs: ["libbase_headers"],
 }
 
+cc_test {
+    name: "libnativebridge-tests",
+    defaults: ["libnativebridge-tests-defaults"],
+    host_supported: true,
+    shared_libs: ["libnativebridge"],
+}
+
+cc_test {
+    name: "libnativebridge-lazy-tests",
+    defaults: ["libnativebridge-tests-defaults"],
+    shared_libs: ["libnativebridge_lazy"],
+}
+
 // Build the test for the C API.
 cc_test {
     name: "libnativebridge-api-tests",
@@ -95,5 +106,5 @@
     srcs: [
         "NativeBridgeApi.c",
     ],
-    header_libs: ["libnativebridge-dummy-headers"],
+    header_libs: ["libnativebridge-headers"],
 }
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
index 1ec21e9..b806ae4 100644
--- a/libnativeloader/Android.bp
+++ b/libnativeloader/Android.bp
@@ -1,7 +1,21 @@
 // Shared library for target
 // ========================================================
+cc_defaults {
+    name: "libnativeloader-defaults",
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+    cppflags: [
+        "-fvisibility=hidden",
+    ],
+    header_libs: ["libnativeloader-headers"],
+    export_header_lib_headers: ["libnativeloader-headers"],
+}
+
 cc_library {
     name: "libnativeloader",
+    defaults: ["libnativeloader-defaults"],
     host_supported: true,
     srcs: ["native_loader.cpp"],
     shared_libs: [
@@ -11,14 +25,6 @@
         "libnativebridge",
         "libbase",
     ],
-    cflags: [
-        "-Werror",
-        "-Wall",
-    ],
-    cppflags: [
-        "-fvisibility=hidden",
-    ],
-    export_include_dirs: ["include"],
     required: [
         "llndk.libraries.txt",
         "vndksp.libraries.txt",
@@ -29,9 +35,25 @@
     },
 }
 
+// TODO(b/124250621) eliminate the need for this library
+cc_library {
+    name: "libnativeloader_lazy",
+    defaults: ["libnativeloader-defaults"],
+    host_supported: false,
+    srcs: ["native_loader_lazy.cpp"],
+    required: ["libnativeloader"],
+}
+
+cc_library_headers {
+    name: "libnativeloader-headers",
+    host_supported: true,
+    export_include_dirs: ["include"],
+}
+
+// TODO(jiyong) Remove this when its use in the internal master is
+// switched to libnativeloader-headers
 cc_library_headers {
     name: "libnativeloader-dummy-headers",
-
     host_supported: true,
     export_include_dirs: ["include"],
 }
diff --git a/libnativeloader/native_loader_lazy.cpp b/libnativeloader/native_loader_lazy.cpp
new file mode 100644
index 0000000..11ecc431
--- /dev/null
+++ b/libnativeloader/native_loader_lazy.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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 "nativeloader/native_loader.h"
+#define LOG_TAG "nativeloader"
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <string.h>
+
+#include <log/log.h>
+
+namespace android {
+
+namespace {
+
+void* GetLibHandle() {
+  static void* handle = dlopen("libnativeloader.so", RTLD_NOW);
+  LOG_FATAL_IF(handle == nullptr, "Failed to load libnativeloader.so: %s", dlerror());
+  return handle;
+}
+
+template <typename FuncPtr>
+FuncPtr GetFuncPtr(const char* function_name) {
+  auto f = reinterpret_cast<FuncPtr>(dlsym(GetLibHandle(), function_name));
+  LOG_FATAL_IF(f == nullptr, "Failed to get address of %s: %s", function_name, dlerror());
+  return f;
+}
+
+#define GET_FUNC_PTR(name) GetFuncPtr<decltype(&name)>(#name)
+
+}  // namespace
+
+void InitializeNativeLoader() {
+  static auto f = GET_FUNC_PTR(InitializeNativeLoader);
+  return f();
+}
+
+jstring CreateClassLoaderNamespace(JNIEnv* env, int32_t target_sdk_version, jobject class_loader,
+                                   bool is_shared, bool is_for_vendor, jstring library_path,
+                                   jstring permitted_path) {
+  static auto f = GET_FUNC_PTR(CreateClassLoaderNamespace);
+  return f(env, target_sdk_version, class_loader, is_shared, is_for_vendor, library_path,
+           permitted_path);
+}
+
+void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
+                        jobject class_loader, const char* caller_location, jstring library_path,
+                        bool* needs_native_bridge, char** error_msg) {
+  static auto f = GET_FUNC_PTR(OpenNativeLibrary);
+  return f(env, target_sdk_version, path, class_loader, caller_location, library_path,
+           needs_native_bridge, error_msg);
+}
+
+bool CloseNativeLibrary(void* handle, const bool needs_native_bridge, char** error_msg) {
+  static auto f = GET_FUNC_PTR(CloseNativeLibrary);
+  return f(handle, needs_native_bridge, error_msg);
+}
+
+void NativeLoaderFreeErrorMessage(char* msg) {
+  static auto f = GET_FUNC_PTR(NativeLoaderFreeErrorMessage);
+  return f(msg);
+}
+
+struct android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
+  static auto f = GET_FUNC_PTR(FindNamespaceByClassLoader);
+  return f(env, class_loader);
+}
+
+struct NativeLoaderNamespace* FindNativeLoaderNamespaceByClassLoader(JNIEnv* env,
+                                                                     jobject class_loader) {
+  static auto f = GET_FUNC_PTR(FindNativeLoaderNamespaceByClassLoader);
+  return f(env, class_loader);
+}
+
+void* OpenNativeLibraryInNamespace(struct NativeLoaderNamespace* ns, const char* path,
+                                   bool* needs_native_bridge, char** error_msg) {
+  static auto f = GET_FUNC_PTR(OpenNativeLibraryInNamespace);
+  return f(ns, path, needs_native_bridge, error_msg);
+}
+
+void ResetNativeLoader() {
+  static auto f = GET_FUNC_PTR(ResetNativeLoader);
+  return f();
+}
+
+#undef GET_FUNC_PTR
+
+}  // namespace android
diff --git a/libnativeloader/test/Android.bp b/libnativeloader/test/Android.bp
index 1464e39..4d5c53d 100644
--- a/libnativeloader/test/Android.bp
+++ b/libnativeloader/test/Android.bp
@@ -78,5 +78,5 @@
     srcs: [
         "api_test.c",
     ],
-    header_libs: ["libnativeloader-dummy-headers"],
+    header_libs: ["libnativeloader-headers"],
 }
diff --git a/lmkd/include/lmkd.h b/lmkd/include/lmkd.h
index e72d159..59377dd 100644
--- a/lmkd/include/lmkd.h
+++ b/lmkd/include/lmkd.h
@@ -50,7 +50,7 @@
 typedef int LMKD_CTRL_PACKET[CTRL_PACKET_MAX_SIZE / sizeof(int)];
 
 /* Get LMKD packet command */
-inline enum lmk_cmd lmkd_pack_get_cmd(LMKD_CTRL_PACKET pack) {
+static inline enum lmk_cmd lmkd_pack_get_cmd(LMKD_CTRL_PACKET pack) {
     return (enum lmk_cmd)ntohl(pack[0]);
 }
 
@@ -64,8 +64,8 @@
  * For LMK_TARGET packet get target_idx-th payload.
  * Warning: no checks performed, caller should ensure valid parameters.
  */
-inline void lmkd_pack_get_target(LMKD_CTRL_PACKET packet,
-                                 int target_idx, struct lmk_target *target) {
+static inline void lmkd_pack_get_target(LMKD_CTRL_PACKET packet, int target_idx,
+                                        struct lmk_target* target) {
     target->minfree = ntohl(packet[target_idx * 2 + 1]);
     target->oom_adj_score = ntohl(packet[target_idx * 2 + 2]);
 }
@@ -74,9 +74,8 @@
  * Prepare LMK_TARGET packet and return packet size in bytes.
  * Warning: no checks performed, caller should ensure valid parameters.
  */
-inline size_t lmkd_pack_set_target(LMKD_CTRL_PACKET packet,
-                                   struct lmk_target *targets,
-                                   size_t target_cnt) {
+static inline size_t lmkd_pack_set_target(LMKD_CTRL_PACKET packet, struct lmk_target* targets,
+                                          size_t target_cnt) {
     int idx = 0;
     packet[idx++] = htonl(LMK_TARGET);
     while (target_cnt) {
@@ -99,8 +98,7 @@
  * For LMK_PROCPRIO packet get its payload.
  * Warning: no checks performed, caller should ensure valid parameters.
  */
-inline void lmkd_pack_get_procprio(LMKD_CTRL_PACKET packet,
-                                   struct lmk_procprio *params) {
+static inline void lmkd_pack_get_procprio(LMKD_CTRL_PACKET packet, struct lmk_procprio* params) {
     params->pid = (pid_t)ntohl(packet[1]);
     params->uid = (uid_t)ntohl(packet[2]);
     params->oomadj = ntohl(packet[3]);
@@ -110,8 +108,7 @@
  * Prepare LMK_PROCPRIO packet and return packet size in bytes.
  * Warning: no checks performed, caller should ensure valid parameters.
  */
-inline size_t lmkd_pack_set_procprio(LMKD_CTRL_PACKET packet,
-                                   struct lmk_procprio *params) {
+static inline size_t lmkd_pack_set_procprio(LMKD_CTRL_PACKET packet, struct lmk_procprio* params) {
     packet[0] = htonl(LMK_PROCPRIO);
     packet[1] = htonl(params->pid);
     packet[2] = htonl(params->uid);
@@ -128,8 +125,8 @@
  * For LMK_PROCREMOVE packet get its payload.
  * Warning: no checks performed, caller should ensure valid parameters.
  */
-inline void lmkd_pack_get_procremove(LMKD_CTRL_PACKET packet,
-                                   struct lmk_procremove *params) {
+static inline void lmkd_pack_get_procremove(LMKD_CTRL_PACKET packet,
+                                            struct lmk_procremove* params) {
     params->pid = (pid_t)ntohl(packet[1]);
 }
 
@@ -137,8 +134,8 @@
  * Prepare LMK_PROCREMOVE packet and return packet size in bytes.
  * Warning: no checks performed, caller should ensure valid parameters.
  */
-inline size_t lmkd_pack_set_procremove(LMKD_CTRL_PACKET packet,
-                                   struct lmk_procprio *params) {
+static inline size_t lmkd_pack_set_procremove(LMKD_CTRL_PACKET packet,
+                                              struct lmk_procprio* params) {
     packet[0] = htonl(LMK_PROCREMOVE);
     packet[1] = htonl(params->pid);
     return 2 * sizeof(int);
@@ -148,7 +145,7 @@
  * Prepare LMK_PROCPURGE packet and return packet size in bytes.
  * Warning: no checks performed, caller should ensure valid parameters.
  */
-inline size_t lmkd_pack_set_procpurge(LMKD_CTRL_PACKET packet) {
+static inline size_t lmkd_pack_set_procpurge(LMKD_CTRL_PACKET packet) {
     packet[0] = htonl(LMK_PROCPURGE);
     return sizeof(int);
 }
@@ -163,8 +160,8 @@
  * For LMK_GETKILLCNT packet get its payload.
  * Warning: no checks performed, caller should ensure valid parameters.
  */
-inline void lmkd_pack_get_getkillcnt(LMKD_CTRL_PACKET packet,
-                                   struct lmk_getkillcnt *params) {
+static inline void lmkd_pack_get_getkillcnt(LMKD_CTRL_PACKET packet,
+                                            struct lmk_getkillcnt* params) {
     params->min_oomadj = ntohl(packet[1]);
     params->max_oomadj = ntohl(packet[2]);
 }
@@ -173,8 +170,8 @@
  * Prepare LMK_GETKILLCNT packet and return packet size in bytes.
  * Warning: no checks performed, caller should ensure valid parameters.
  */
-inline size_t lmkd_pack_set_getkillcnt(LMKD_CTRL_PACKET packet,
-                                       struct lmk_getkillcnt *params) {
+static inline size_t lmkd_pack_set_getkillcnt(LMKD_CTRL_PACKET packet,
+                                              struct lmk_getkillcnt* params) {
     packet[0] = htonl(LMK_GETKILLCNT);
     packet[1] = htonl(params->min_oomadj);
     packet[2] = htonl(params->max_oomadj);
@@ -185,7 +182,7 @@
  * Prepare LMK_GETKILLCNT reply packet and return packet size in bytes.
  * Warning: no checks performed, caller should ensure valid parameters.
  */
-inline size_t lmkd_pack_set_getkillcnt_repl(LMKD_CTRL_PACKET packet, int kill_cnt) {
+static inline size_t lmkd_pack_set_getkillcnt_repl(LMKD_CTRL_PACKET packet, int kill_cnt) {
     packet[0] = htonl(LMK_GETKILLCNT);
     packet[1] = htonl(kill_cnt);
     return 2 * sizeof(int);
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 2a44ae4..df9abbd 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -20,13 +20,17 @@
 dir.vendor = /data/benchmarktest/vendor
 dir.vendor = /data/benchmarktest64/vendor
 
+dir.unrestricted = /data/nativetest/unrestricted
+dir.unrestricted = /data/nativetest64/unrestricted
+
+# TODO(b/123864775): Ensure tests are run from /data/nativetest{,64} or (if
+# necessary) the unrestricted subdirs above. Then clean this up.
+dir.unrestricted = /data/local/tmp
+
 dir.system = /data/nativetest
 dir.system = /data/nativetest64
 dir.system = /data/benchmarktest
 dir.system = /data/benchmarktest64
-# TODO(b/123864775): Ensure tests are run from one of the directories above and
-# remove this.
-dir.system = /data/local/tmp
 
 dir.postinstall = /postinstall
 
@@ -409,6 +413,7 @@
 
 # Keep in sync with ld.config.txt in the com.android.runtime APEX.
 namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
 namespace.runtime.links = system
 # TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
 # when it exists.
@@ -477,6 +482,111 @@
 namespace.system.link.runtime.shared_libs += libnativehelper.so
 namespace.system.link.runtime.shared_libs += libnativeloader.so
 
+
+###############################################################################
+# Namespace config for native tests that need access to both system and vendor
+# libraries. This replicates the default linker config (done by
+# init_default_namespace_no_config in bionic/linker/linker.cpp), except that it
+# includes the requisite namespace setup for APEXes.
+###############################################################################
+[unrestricted]
+additional.namespaces = runtime,media,conscrypt,resolv
+
+namespace.default.search.paths  = /system/${LIB}
+namespace.default.search.paths += /odm/${LIB}
+namespace.default.search.paths += /vendor/${LIB}
+
+namespace.default.asan.search.paths  = /data/asan/system/${LIB}
+namespace.default.asan.search.paths +=           /system/${LIB}
+namespace.default.asan.search.paths += /data/asan/odm/${LIB}
+namespace.default.asan.search.paths +=           /odm/${LIB}
+namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
+namespace.default.asan.search.paths +=           /vendor/${LIB}
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.default.links = runtime,resolv
+namespace.default.visible = true
+
+namespace.default.link.runtime.shared_libs  = libart.so:libartd.so
+namespace.default.link.runtime.shared_libs += libdexfile_external.so
+namespace.default.link.runtime.shared_libs += libnativebridge.so
+namespace.default.link.runtime.shared_libs += libnativehelper.so
+namespace.default.link.runtime.shared_libs += libnativeloader.so
+namespace.default.link.runtime.shared_libs += libandroidicu.so
+
+# TODO(b/122876336): Remove libpac.so once it's migrated to Webview
+namespace.default.link.runtime.shared_libs += libpac.so
+
+namespace.default.link.resolv.shared_libs = libnetd_resolv.so
+
+###############################################################################
+# "runtime" APEX namespace
+#
+# This namespace exposes externally accessible libraries from the Runtime APEX.
+###############################################################################
+namespace.runtime.isolated = true
+namespace.runtime.visible = true
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.links = default
+# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
+# when it exists.
+namespace.runtime.link.default.allow_all_shared_libs = true
+
+###############################################################################
+# "media" APEX namespace
+#
+# This namespace is for libraries within the media APEX.
+###############################################################################
+namespace.media.isolated = true
+namespace.media.visible = true
+
+namespace.media.search.paths = /apex/com.android.media/${LIB}
+namespace.media.asan.search.paths = /apex/com.android.media/${LIB}
+
+namespace.media.links = default
+namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
+namespace.media.link.default.shared_libs += libandroid.so
+namespace.media.link.default.shared_libs += libbinder_ndk.so
+namespace.media.link.default.shared_libs += libmediametrics.so
+namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+
+###############################################################################
+# "conscrypt" APEX namespace
+#
+# This namespace is for libraries within the conscrypt APEX.
+###############################################################################
+namespace.conscrypt.isolated = true
+namespace.conscrypt.visible = true
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
+namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
+namespace.conscrypt.links = runtime,default
+namespace.conscrypt.link.runtime.shared_libs  = libjavacore.so
+namespace.conscrypt.link.default.shared_libs  = libc.so
+namespace.conscrypt.link.default.shared_libs += libm.so
+namespace.conscrypt.link.default.shared_libs += libdl.so
+
+###############################################################################
+# "resolv" APEX namespace
+#
+# This namespace is for libraries within the resolv APEX.
+###############################################################################
+namespace.resolv.isolated = true
+namespace.resolv.visible = true
+
+namespace.resolv.search.paths = /apex/com.android.resolv/${LIB}
+namespace.resolv.asan.search.paths = /apex/com.android.resolv/${LIB}
+namespace.resolv.links = default
+namespace.resolv.link.default.shared_libs  = libc.so
+namespace.resolv.link.default.shared_libs += libm.so
+namespace.resolv.link.default.shared_libs += libdl.so
+namespace.resolv.link.default.shared_libs += libbinder_ndk.so
+
+
 ###############################################################################
 # Namespace config for binaries under /postinstall.
 # Only default namespace is defined and default has no directories
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index 95195b5..3c97a49 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -306,11 +306,11 @@
 namespace.default.search.paths += /vendor/${LIB}/vndk-sp
 
 # Access to system libraries is allowed
-namespace.default.search.paths += /system/${LIB}/vndk%VNDK_VER%
 namespace.default.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
 namespace.default.search.paths += /system/${LIB}
 namespace.default.search.paths += /%PRODUCT%/${LIB}
 namespace.default.search.paths += /%PRODUCT_SERVICES%/${LIB}
+namespace.default.search.paths += /system/${LIB}/vndk%VNDK_VER%
 
 namespace.default.asan.search.paths  = /data/asan/odm/${LIB}
 namespace.default.asan.search.paths +=           /odm/${LIB}
@@ -324,8 +324,6 @@
 namespace.default.asan.search.paths +=           /vendor/${LIB}/vndk
 namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
 namespace.default.asan.search.paths +=           /vendor/${LIB}/vndk-sp
-namespace.default.asan.search.paths += /data/asan/system/${LIB}/vndk%VNDK_VER%
-namespace.default.asan.search.paths +=           /system/${LIB}/vndk%VNDK_VER%
 namespace.default.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
 namespace.default.asan.search.paths +=           /system/${LIB}/vndk-sp%VNDK_VER%
 namespace.default.asan.search.paths += /data/asan/system/${LIB}
@@ -334,6 +332,8 @@
 namespace.default.asan.search.paths +=           /%PRODUCT%/${LIB}
 namespace.default.asan.search.paths += /data/asan/product_services/${LIB}
 namespace.default.asan.search.paths +=           /%PRODUCT_SERVICES%/${LIB}
+namespace.default.asan.search.paths += /data/asan/system/${LIB}/vndk%VNDK_VER%
+namespace.default.asan.search.paths +=           /system/${LIB}/vndk%VNDK_VER%
 
 namespace.default.links = runtime
 namespace.default.link.runtime.shared_libs  = libdexfile_external.so
@@ -350,6 +350,7 @@
 
 # Keep in sync with ld.config.txt in the com.android.runtime APEX.
 namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
 namespace.runtime.links = default
 # TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
 # when it exists.