Merge changes Ie5ec609a,I5a2ac369,I690137b5

* changes:
  ueventd: Fix up string handling in handle_*_device_event()
  ueventd: convert mkdir_recursive() to std::string
  ueventd: move subsystem logic from code to ueventd.rc
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 120129c..78d0c07 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -707,6 +707,23 @@
     }
 }
 
+static std::string extract_by_name_prefix(struct fstab* fstab) {
+    // We assume that there's an entry for the /misc mount point in the
+    // fstab file and use that to get the device file by-name prefix.
+    // The device needs not to have an actual /misc partition.
+    // e.g.,
+    //    - /dev/block/platform/soc.0/7824900.sdhci/by-name/misc ->
+    //    - /dev/block/platform/soc.0/7824900.sdhci/by-name/
+    struct fstab_rec* fstab_entry = fs_mgr_get_entry_for_mount_point(fstab, "/misc");
+    if (fstab_entry == nullptr) {
+        LERROR << "/misc mount point not found in fstab";
+        return "";
+    }
+    std::string full_path(fstab_entry->blk_device);
+    size_t end_slash = full_path.find_last_of("/");
+    return full_path.substr(0, end_slash + 1);
+}
+
 // TODO: add ueventd notifiers if they don't exist.
 // This is just doing a wait_for_device for maximum of 1s
 int fs_mgr_test_access(const char *device) {
@@ -750,17 +767,12 @@
     int mret = -1;
     int mount_errno = 0;
     int attempted_idx = -1;
-    int avb_ret = FS_MGR_SETUP_AVB_FAIL;
+    FsManagerAvbUniquePtr avb_handle(nullptr);
 
     if (!fstab) {
         return -1;
     }
 
-    if (fs_mgr_is_avb_used() &&
-        (avb_ret = fs_mgr_load_vbmeta_images(fstab)) == FS_MGR_SETUP_AVB_FAIL) {
-        return -1;
-    }
-
     for (i = 0; i < fstab->num_entries; i++) {
         /* Don't mount entries that are managed by vold or not for the mount mode*/
         if ((fstab->recs[i].fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) ||
@@ -799,16 +811,15 @@
             wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
         }
 
-        if (fs_mgr_is_avb_used() && (fstab->recs[i].fs_mgr_flags & MF_AVB)) {
-            /* If HASHTREE_DISABLED is set (cf. 'adb disable-verity'), we
-             * should set up the device without using dm-verity.
-             * The actual mounting still take place in the following
-             * mount_with_alternatives().
-             */
-            if (avb_ret == FS_MGR_SETUP_AVB_HASHTREE_DISABLED) {
-                LINFO << "AVB HASHTREE disabled";
-            } else if (fs_mgr_setup_avb(&fstab->recs[i]) !=
-                       FS_MGR_SETUP_AVB_SUCCESS) {
+        if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
+            if (!avb_handle) {
+                avb_handle = FsManagerAvbHandle::Open(extract_by_name_prefix(fstab));
+                if (!avb_handle) {
+                    LERROR << "Failed to open FsManagerAvbHandle";
+                    return -1;
+                }
+            }
+            if (!avb_handle->SetUpAvb(&fstab->recs[i])) {
                 LERROR << "Failed to set up AVB on partition: "
                        << fstab->recs[i].mount_point << ", skipping!";
                 /* Skips mounting the device. */
@@ -934,10 +945,6 @@
         }
     }
 
-    if (fs_mgr_is_avb_used()) {
-        fs_mgr_unload_vbmeta_images();
-    }
-
     if (error_count) {
         return -1;
     } else {
@@ -976,17 +983,12 @@
     int mount_errors = 0;
     int first_mount_errno = 0;
     char *m;
-    int avb_ret = FS_MGR_SETUP_AVB_FAIL;
+    FsManagerAvbUniquePtr avb_handle(nullptr);
 
     if (!fstab) {
         return ret;
     }
 
-    if (fs_mgr_is_avb_used() &&
-        (avb_ret = fs_mgr_load_vbmeta_images(fstab)) == FS_MGR_SETUP_AVB_FAIL) {
-        return ret;
-    }
-
     for (i = 0; i < fstab->num_entries; i++) {
         if (!fs_match(fstab->recs[i].mount_point, n_name)) {
             continue;
@@ -1021,16 +1023,15 @@
             do_reserved_size(n_blk_device, fstab->recs[i].fs_type, &fstab->recs[i], &fs_stat);
         }
 
-        if (fs_mgr_is_avb_used() && (fstab->recs[i].fs_mgr_flags & MF_AVB)) {
-            /* If HASHTREE_DISABLED is set (cf. 'adb disable-verity'), we
-             * should set up the device without using dm-verity.
-             * The actual mounting still take place in the following
-             * mount_with_alternatives().
-             */
-            if (avb_ret == FS_MGR_SETUP_AVB_HASHTREE_DISABLED) {
-                LINFO << "AVB HASHTREE disabled";
-            } else if (fs_mgr_setup_avb(&fstab->recs[i]) !=
-                       FS_MGR_SETUP_AVB_SUCCESS) {
+        if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
+            if (!avb_handle) {
+                avb_handle = FsManagerAvbHandle::Open(extract_by_name_prefix(fstab));
+                if (!avb_handle) {
+                    LERROR << "Failed to open FsManagerAvbHandle";
+                    return -1;
+                }
+            }
+            if (!avb_handle->SetUpAvb(&fstab->recs[i])) {
                 LERROR << "Failed to set up AVB on partition: "
                        << fstab->recs[i].mount_point << ", skipping!";
                 /* Skips mounting the device. */
@@ -1079,9 +1080,6 @@
     }
 
 out:
-    if (fs_mgr_is_avb_used()) {
-        fs_mgr_unload_vbmeta_images();
-    }
     return ret;
 }
 
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index 7512eb9..76ec236 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -28,6 +28,7 @@
 #include <android-base/file.h>
 #include <android-base/parseint.h>
 #include <android-base/properties.h>
+#include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <cutils/properties.h>
@@ -85,24 +86,6 @@
         hashtree_desc.fec_offset / hashtree_desc.data_block_size, /* fec_start */  \
         VERITY_TABLE_OPT_IGNZERO, VERITY_TABLE_OPT_RESTART
 
-AvbSlotVerifyData* fs_mgr_avb_verify_data = nullptr;
-AvbOps* fs_mgr_avb_ops = nullptr;
-
-enum HashAlgorithm {
-    kInvalid = 0,
-    kSHA256 = 1,
-    kSHA512 = 2,
-};
-
-struct androidboot_vbmeta {
-    HashAlgorithm hash_alg;
-    uint8_t digest[SHA512_DIGEST_LENGTH];
-    size_t vbmeta_size;
-    bool allow_verification_error;
-};
-
-androidboot_vbmeta fs_mgr_vbmeta_prop;
-
 static inline bool nibble_value(const char& c, uint8_t* value) {
     FS_MGR_CHECK(value != nullptr);
 
@@ -159,27 +142,78 @@
     return hex;
 }
 
-static bool load_vbmeta_prop(androidboot_vbmeta* vbmeta_prop) {
-    FS_MGR_CHECK(vbmeta_prop != nullptr);
+template <typename Hasher>
+static std::pair<size_t, bool> verify_vbmeta_digest(const AvbSlotVerifyData& verify_data,
+                                                    const uint8_t* expected_digest) {
+    size_t total_size = 0;
+    Hasher hasher;
+    for (size_t n = 0; n < verify_data.num_vbmeta_images; n++) {
+        hasher.update(verify_data.vbmeta_images[n].vbmeta_data,
+                      verify_data.vbmeta_images[n].vbmeta_size);
+        total_size += verify_data.vbmeta_images[n].vbmeta_size;
+    }
 
+    bool matched = (memcmp(hasher.finalize(), expected_digest, Hasher::DIGEST_SIZE) == 0);
+
+    return std::make_pair(total_size, matched);
+}
+
+// Reads the following values from kernel cmdline and provides the
+// VerifyVbmetaImages() to verify AvbSlotVerifyData.
+//   - androidboot.vbmeta.device_state
+//   - androidboot.vbmeta.hash_alg
+//   - androidboot.vbmeta.size
+//   - androidboot.vbmeta.digest
+class FsManagerAvbVerifier {
+  public:
+    // The factory method to return a unique_ptr<FsManagerAvbVerifier>
+    static std::unique_ptr<FsManagerAvbVerifier> Create();
+    bool VerifyVbmetaImages(const AvbSlotVerifyData& verify_data);
+    bool IsDeviceUnlocked() { return is_device_unlocked_; }
+
+  protected:
+    FsManagerAvbVerifier() = default;
+
+  private:
+    enum HashAlgorithm {
+        kInvalid = 0,
+        kSHA256 = 1,
+        kSHA512 = 2,
+    };
+
+    HashAlgorithm hash_alg_;
+    uint8_t digest_[SHA512_DIGEST_LENGTH];
+    size_t vbmeta_size_;
+    bool is_device_unlocked_;
+};
+
+std::unique_ptr<FsManagerAvbVerifier> FsManagerAvbVerifier::Create() {
     std::string cmdline;
-    android::base::ReadFileToString("/proc/cmdline", &cmdline);
+    if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
+        LERROR << "Failed to read /proc/cmdline";
+        return nullptr;
+    }
 
-    std::string hash_alg;
+    std::unique_ptr<FsManagerAvbVerifier> avb_verifier(new FsManagerAvbVerifier());
+    if (!avb_verifier) {
+        LERROR << "Failed to create unique_ptr<FsManagerAvbVerifier>";
+        return nullptr;
+    }
+
     std::string digest;
-
+    std::string hash_alg;
     for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) {
         std::vector<std::string> pieces = android::base::Split(entry, "=");
         const std::string& key = pieces[0];
         const std::string& value = pieces[1];
 
         if (key == "androidboot.vbmeta.device_state") {
-            vbmeta_prop->allow_verification_error = (value == "unlocked");
+            avb_verifier->is_device_unlocked_ = (value == "unlocked");
         } else if (key == "androidboot.vbmeta.hash_alg") {
             hash_alg = value;
         } else if (key == "androidboot.vbmeta.size") {
-            if (!android::base::ParseUint(value.c_str(), &vbmeta_prop->vbmeta_size)) {
-                return false;
+            if (!android::base::ParseUint(value.c_str(), &avb_verifier->vbmeta_size_)) {
+                return nullptr;
             }
         } else if (key == "androidboot.vbmeta.digest") {
             digest = value;
@@ -190,48 +224,31 @@
     size_t expected_digest_size = 0;
     if (hash_alg == "sha256") {
         expected_digest_size = SHA256_DIGEST_LENGTH * 2;
-        vbmeta_prop->hash_alg = kSHA256;
+        avb_verifier->hash_alg_ = kSHA256;
     } else if (hash_alg == "sha512") {
         expected_digest_size = SHA512_DIGEST_LENGTH * 2;
-        vbmeta_prop->hash_alg = kSHA512;
+        avb_verifier->hash_alg_ = kSHA512;
     } else {
         LERROR << "Unknown hash algorithm: " << hash_alg.c_str();
-        return false;
+        return nullptr;
     }
 
     // Reads digest.
     if (digest.size() != expected_digest_size) {
         LERROR << "Unexpected digest size: " << digest.size()
                << " (expected: " << expected_digest_size << ")";
-        return false;
+        return nullptr;
     }
 
-    if (!hex_to_bytes(vbmeta_prop->digest, sizeof(vbmeta_prop->digest), digest)) {
+    if (!hex_to_bytes(avb_verifier->digest_, sizeof(avb_verifier->digest_), digest)) {
         LERROR << "Hash digest contains non-hexidecimal character: " << digest.c_str();
-        return false;
+        return nullptr;
     }
 
-    return true;
+    return avb_verifier;
 }
 
-template <typename Hasher>
-static std::pair<size_t, bool> verify_vbmeta_digest(const AvbSlotVerifyData& verify_data,
-                                                    const androidboot_vbmeta& vbmeta_prop) {
-    size_t total_size = 0;
-    Hasher hasher;
-    for (size_t n = 0; n < verify_data.num_vbmeta_images; n++) {
-        hasher.update(verify_data.vbmeta_images[n].vbmeta_data,
-                      verify_data.vbmeta_images[n].vbmeta_size);
-        total_size += verify_data.vbmeta_images[n].vbmeta_size;
-    }
-
-    bool matched = (memcmp(hasher.finalize(), vbmeta_prop.digest, Hasher::DIGEST_SIZE) == 0);
-
-    return std::make_pair(total_size, matched);
-}
-
-static bool verify_vbmeta_images(const AvbSlotVerifyData& verify_data,
-                                 const androidboot_vbmeta& vbmeta_prop) {
+bool FsManagerAvbVerifier::VerifyVbmetaImages(const AvbSlotVerifyData& verify_data) {
     if (verify_data.num_vbmeta_images == 0) {
         LERROR << "No vbmeta images";
         return false;
@@ -240,17 +257,17 @@
     size_t total_size = 0;
     bool digest_matched = false;
 
-    if (vbmeta_prop.hash_alg == kSHA256) {
+    if (hash_alg_ == kSHA256) {
         std::tie(total_size, digest_matched) =
-            verify_vbmeta_digest<SHA256Hasher>(verify_data, vbmeta_prop);
-    } else if (vbmeta_prop.hash_alg == kSHA512) {
+            verify_vbmeta_digest<SHA256Hasher>(verify_data, digest_);
+    } else if (hash_alg_ == kSHA512) {
         std::tie(total_size, digest_matched) =
-            verify_vbmeta_digest<SHA512Hasher>(verify_data, vbmeta_prop);
+            verify_vbmeta_digest<SHA512Hasher>(verify_data, digest_);
     }
 
-    if (total_size != vbmeta_prop.vbmeta_size) {
-        LERROR << "total vbmeta size mismatch: " << total_size
-               << " (expected: " << vbmeta_prop.vbmeta_size << ")";
+    if (total_size != vbmeta_size_) {
+        LERROR << "total vbmeta size mismatch: " << total_size << " (expected: " << vbmeta_size_
+               << ")";
         return false;
     }
 
@@ -408,8 +425,7 @@
                 continue;
             }
             if (desc.tag == AVB_DESCRIPTOR_TAG_HASHTREE) {
-                desc_partition_name =
-                    (const uint8_t*)descriptors[j] + sizeof(AvbHashtreeDescriptor);
+                desc_partition_name = (const uint8_t*)descriptors[j] + sizeof(AvbHashtreeDescriptor);
                 if (!avb_hashtree_descriptor_validate_and_byteswap(
                         (AvbHashtreeDescriptor*)descriptors[j], out_hashtree_desc)) {
                     continue;
@@ -441,140 +457,96 @@
     return true;
 }
 
-static bool init_is_avb_used() {
-    // When AVB is used, boot loader should set androidboot.vbmeta.{hash_alg,
-    // size, digest} in kernel cmdline or in device tree. They will then be
-    // imported by init process to system properties: ro.boot.vbmeta.{hash_alg, size, digest}.
-    //
-    // In case of early mount, init properties are not initialized, so we also
-    // ensure we look into kernel command line and device tree if the property is
-    // not found
-    //
-    // Checks hash_alg as an indicator for whether AVB is used.
-    // We don't have to parse and check all of them here. The check will
-    // be done in fs_mgr_load_vbmeta_images() and FS_MGR_SETUP_AVB_FAIL will
-    // be returned when there is an error.
-
-    std::string hash_alg;
-    if (!fs_mgr_get_boot_config("vbmeta.hash_alg", &hash_alg)) {
-        return false;
-    }
-    if (hash_alg == "sha256" || hash_alg == "sha512") {
-        return true;
-    }
-    return false;
-}
-
-bool fs_mgr_is_avb_used() {
-    static bool result = init_is_avb_used();
-    return result;
-}
-
-int fs_mgr_load_vbmeta_images(struct fstab* fstab) {
-    FS_MGR_CHECK(fstab != nullptr);
-
-    // Gets the expected hash value of vbmeta images from
-    // kernel cmdline.
-    if (!load_vbmeta_prop(&fs_mgr_vbmeta_prop)) {
-        return FS_MGR_SETUP_AVB_FAIL;
+FsManagerAvbUniquePtr FsManagerAvbHandle::Open(const std::string& device_file_by_name_prefix) {
+    if (device_file_by_name_prefix.empty()) {
+        LERROR << "Missing device file by-name prefix";
+        return nullptr;
     }
 
-    fs_mgr_avb_ops = fs_mgr_dummy_avb_ops_new(fstab);
-    if (fs_mgr_avb_ops == nullptr) {
-        LERROR << "Failed to allocate dummy avb_ops";
-        return FS_MGR_SETUP_AVB_FAIL;
+    // Gets the expected hash value of vbmeta images from kernel cmdline.
+    std::unique_ptr<FsManagerAvbVerifier> avb_verifier = FsManagerAvbVerifier::Create();
+    if (!avb_verifier) {
+        LERROR << "Failed to create FsManagerAvbVerifier";
+        return nullptr;
     }
 
-    // Invokes avb_slot_verify() to load and verify all vbmeta images.
-    // Sets requested_partitions to nullptr as it's to copy the contents
-    // of HASH partitions into fs_mgr_avb_verify_data, which is not required as
-    // fs_mgr only deals with HASHTREE partitions.
-    const char *requested_partitions[] = {nullptr};
-    std::string ab_suffix;
-    std::string slot;
-    if (fs_mgr_get_boot_config("slot", &slot)) {
-        ab_suffix = "_" + slot;
-    } else {
-        // remove slot_suffix once bootloaders update to new androidboot.slot param
-        fs_mgr_get_boot_config("slot_suffix", &ab_suffix);
+    FsManagerAvbUniquePtr avb_handle(new FsManagerAvbHandle());
+    if (!avb_handle) {
+        LERROR << "Failed to allocate FsManagerAvbHandle";
+        return nullptr;
     }
-    AvbSlotVerifyResult verify_result =
-        avb_slot_verify(fs_mgr_avb_ops, requested_partitions, ab_suffix.c_str(),
-                        fs_mgr_vbmeta_prop.allow_verification_error, &fs_mgr_avb_verify_data);
+
+    FsManagerAvbOps avb_ops(device_file_by_name_prefix);
+    AvbSlotVerifyResult verify_result = avb_ops.AvbSlotVerify(
+        fs_mgr_get_slot_suffix(), avb_verifier->IsDeviceUnlocked(), &avb_handle->avb_slot_data_);
 
     // Only allow two verify results:
     //   - AVB_SLOT_VERIFY_RESULT_OK.
     //   - AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION (for UNLOCKED state).
     if (verify_result == AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION) {
-        if (!fs_mgr_vbmeta_prop.allow_verification_error) {
+        if (!avb_verifier->IsDeviceUnlocked()) {
             LERROR << "ERROR_VERIFICATION isn't allowed";
-            goto fail;
+            return nullptr;
         }
     } else if (verify_result != AVB_SLOT_VERIFY_RESULT_OK) {
         LERROR << "avb_slot_verify failed, result: " << verify_result;
-        goto fail;
+        return nullptr;
     }
 
     // Verifies vbmeta images against the digest passed from bootloader.
-    if (!verify_vbmeta_images(*fs_mgr_avb_verify_data, fs_mgr_vbmeta_prop)) {
-        LERROR << "verify_vbmeta_images failed";
-        goto fail;
+    if (!avb_verifier->VerifyVbmetaImages(*avb_handle->avb_slot_data_)) {
+        LERROR << "VerifyVbmetaImages failed";
+        return nullptr;
     } else {
         // Checks whether FLAGS_HASHTREE_DISABLED is set.
         AvbVBMetaImageHeader vbmeta_header;
         avb_vbmeta_image_header_to_host_byte_order(
-            (AvbVBMetaImageHeader*)fs_mgr_avb_verify_data->vbmeta_images[0].vbmeta_data,
+            (AvbVBMetaImageHeader*)avb_handle->avb_slot_data_->vbmeta_images[0].vbmeta_data,
             &vbmeta_header);
 
         bool hashtree_disabled =
             ((AvbVBMetaImageFlags)vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
         if (hashtree_disabled) {
-            return FS_MGR_SETUP_AVB_HASHTREE_DISABLED;
+            avb_handle->status_ = kFsManagerAvbHandleHashtreeDisabled;
+            return avb_handle;
         }
     }
 
     if (verify_result == AVB_SLOT_VERIFY_RESULT_OK) {
-        return FS_MGR_SETUP_AVB_SUCCESS;
+        avb_handle->status_ = kFsManagerAvbHandleSuccess;
+        return avb_handle;
     }
-
-fail:
-    fs_mgr_unload_vbmeta_images();
-    return FS_MGR_SETUP_AVB_FAIL;
+    return nullptr;
 }
 
-void fs_mgr_unload_vbmeta_images() {
-    if (fs_mgr_avb_verify_data != nullptr) {
-        avb_slot_verify_data_free(fs_mgr_avb_verify_data);
+bool FsManagerAvbHandle::SetUpAvb(struct fstab_rec* fstab_entry) {
+    if (!fstab_entry) return false;
+    if (!avb_slot_data_ || avb_slot_data_->num_vbmeta_images < 1) {
+        return false;
     }
-
-    if (fs_mgr_avb_ops != nullptr) {
-        fs_mgr_dummy_avb_ops_free(fs_mgr_avb_ops);
+    if (status_ == kFsManagerAvbHandleHashtreeDisabled) {
+        LINFO << "AVB HASHTREE disabled on:" << fstab_entry->mount_point;
+        return true;
     }
-}
-
-int fs_mgr_setup_avb(struct fstab_rec* fstab_entry) {
-    if (!fstab_entry || !fs_mgr_avb_verify_data || fs_mgr_avb_verify_data->num_vbmeta_images < 1) {
-        return FS_MGR_SETUP_AVB_FAIL;
-    }
+    if (status_ != kFsManagerAvbHandleSuccess) return false;
 
     std::string partition_name(basename(fstab_entry->mount_point));
     if (!avb_validate_utf8((const uint8_t*)partition_name.c_str(), partition_name.length())) {
         LERROR << "Partition name: " << partition_name.c_str() << " is not valid UTF-8.";
-        return FS_MGR_SETUP_AVB_FAIL;
+        return false;
     }
 
     AvbHashtreeDescriptor hashtree_descriptor;
     std::string salt;
     std::string root_digest;
-    if (!get_hashtree_descriptor(partition_name, *fs_mgr_avb_verify_data, &hashtree_descriptor,
-                                 &salt, &root_digest)) {
-        return FS_MGR_SETUP_AVB_FAIL;
+    if (!get_hashtree_descriptor(partition_name, *avb_slot_data_, &hashtree_descriptor, &salt,
+                                 &root_digest)) {
+        return false;
     }
 
     // Converts HASHTREE descriptor to verity_table_params.
     if (!hashtree_dm_verity_setup(fstab_entry, hashtree_descriptor, salt, root_digest)) {
-        return FS_MGR_SETUP_AVB_FAIL;
+        return false;
     }
-
-    return FS_MGR_SETUP_AVB_SUCCESS;
+    return true;
 }
diff --git a/fs_mgr/fs_mgr_avb_ops.cpp b/fs_mgr/fs_mgr_avb_ops.cpp
index 8e49663..981e9fc 100644
--- a/fs_mgr/fs_mgr_avb_ops.cpp
+++ b/fs_mgr/fs_mgr_avb_ops.cpp
@@ -39,91 +39,10 @@
 #include "fs_mgr_avb_ops.h"
 #include "fs_mgr_priv.h"
 
-static std::string fstab_by_name_prefix;
-
-static std::string extract_by_name_prefix(struct fstab* fstab) {
-    // In AVB, we can assume that there's an entry for the /misc mount
-    // point in the fstab file and use that to get the device file for
-    // the misc partition. The device needs not to have an actual /misc
-    // partition. Then returns the prefix by removing the trailing "misc":
-    //
-    //    - /dev/block/platform/soc.0/7824900.sdhci/by-name/misc ->
-    //    - /dev/block/platform/soc.0/7824900.sdhci/by-name/
-
-    struct fstab_rec* fstab_entry = fs_mgr_get_entry_for_mount_point(fstab, "/misc");
-    if (fstab_entry == nullptr) {
-        LERROR << "/misc mount point not found in fstab";
-        return "";
-    }
-
-    std::string full_path(fstab_entry->blk_device);
-    size_t end_slash = full_path.find_last_of("/");
-
-    return full_path.substr(0, end_slash + 1);
-}
-
-static AvbIOResult read_from_partition(AvbOps* ops ATTRIBUTE_UNUSED, const char* partition,
-                                       int64_t offset, size_t num_bytes, void* buffer,
-                                       size_t* out_num_read) {
-    // The input |partition| name is with ab_suffix, e.g. system_a.
-    // Slot suffix (e.g. _a) will be appended to the device file path
-    // for partitions having 'slotselect' optin in fstab file, but it
-    // won't be appended to the mount point.
-    //
-    // Appends |partition| to the fstab_by_name_prefix, which is obtained
-    // by removing the trailing "misc" from the device file of /misc mount
-    // point. e.g.,
-    //
-    //    - /dev/block/platform/soc.0/7824900.sdhci/by-name/ ->
-    //    - /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a
-
-    std::string path = fstab_by_name_prefix + partition;
-
-    // Ensures the device path (a symlink created by init) is ready to
-    // access. fs_mgr_test_access() will test a few iterations if the
-    // path doesn't exist yet.
-    if (fs_mgr_test_access(path.c_str()) < 0) {
-        return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
-    }
-
-    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
-
-    if (fd < 0) {
-        PERROR << "Failed to open " << path.c_str();
-        return AVB_IO_RESULT_ERROR_IO;
-    }
-
-    // If offset is negative, interprets its absolute value as the
-    //  number of bytes from the end of the partition.
-    if (offset < 0) {
-        off64_t total_size = lseek64(fd, 0, SEEK_END);
-        if (total_size == -1) {
-            LERROR << "Failed to lseek64 to end of the partition";
-            return AVB_IO_RESULT_ERROR_IO;
-        }
-        offset = total_size + offset;
-        // Repositions the offset to the beginning.
-        if (lseek64(fd, 0, SEEK_SET) == -1) {
-            LERROR << "Failed to lseek64 to the beginning of the partition";
-            return AVB_IO_RESULT_ERROR_IO;
-        }
-    }
-
-    // On Linux, we never get partial reads from block devices (except
-    // for EOF).
-    ssize_t num_read = TEMP_FAILURE_RETRY(pread64(fd, buffer, num_bytes, offset));
-
-    if (num_read < 0 || (size_t)num_read != num_bytes) {
-        PERROR << "Failed to read " << num_bytes << " bytes from " << path.c_str() << " offset "
-               << offset;
-        return AVB_IO_RESULT_ERROR_IO;
-    }
-
-    if (out_num_read != nullptr) {
-        *out_num_read = num_read;
-    }
-
-    return AVB_IO_RESULT_OK;
+static AvbIOResult read_from_partition(AvbOps* ops, const char* partition, int64_t offset,
+                                       size_t num_bytes, void* buffer, size_t* out_num_read) {
+    return FsManagerAvbOps::GetInstanceFromAvbOps(ops)->ReadFromPartition(
+        partition, offset, num_bytes, buffer, out_num_read);
 }
 
 static AvbIOResult dummy_read_rollback_index(AvbOps* ops ATTRIBUTE_UNUSED,
@@ -145,7 +64,6 @@
     // Addtionally, user-space should check
     // androidboot.vbmeta.{hash_alg, size, digest} against the digest
     // of all vbmeta images after invoking avb_slot_verify().
-
     *out_is_trusted = true;
     return AVB_IO_RESULT_OK;
 }
@@ -170,28 +88,86 @@
     return AVB_IO_RESULT_OK;
 }
 
-AvbOps* fs_mgr_dummy_avb_ops_new(struct fstab* fstab) {
-    AvbOps* ops;
-
-    fstab_by_name_prefix = extract_by_name_prefix(fstab);
-    if (fstab_by_name_prefix.empty()) return nullptr;
-
-    ops = (AvbOps*)calloc(1, sizeof(AvbOps));
-    if (ops == nullptr) {
-        LERROR << "Error allocating memory for AvbOps";
-        return nullptr;
+FsManagerAvbOps::FsManagerAvbOps(const std::string& device_file_by_name_prefix)
+    : device_file_by_name_prefix_(device_file_by_name_prefix) {
+    if (device_file_by_name_prefix_.back() != '/') {
+        device_file_by_name_prefix_ += '/';
     }
+    // We only need to provide the implementation of read_from_partition()
+    // operation since that's all what is being used by the avb_slot_verify().
+    // Other I/O operations are only required in bootloader but not in
+    // user-space so we set them as dummy operations.
+    avb_ops_.read_from_partition = read_from_partition;
+    avb_ops_.read_rollback_index = dummy_read_rollback_index;
+    avb_ops_.validate_vbmeta_public_key = dummy_validate_vbmeta_public_key;
+    avb_ops_.read_is_device_unlocked = dummy_read_is_device_unlocked;
+    avb_ops_.get_unique_guid_for_partition = dummy_get_unique_guid_for_partition;
 
-    // We only need these operations since that's all what is being used
-    // by the avb_slot_verify(); Most of them are dummy operations because
-    // they're only required in bootloader but not required in user-space.
-    ops->read_from_partition = read_from_partition;
-    ops->read_rollback_index = dummy_read_rollback_index;
-    ops->validate_vbmeta_public_key = dummy_validate_vbmeta_public_key;
-    ops->read_is_device_unlocked = dummy_read_is_device_unlocked;
-    ops->get_unique_guid_for_partition = dummy_get_unique_guid_for_partition;
-
-    return ops;
+    // Sets user_data for GetInstanceFromAvbOps() to convert it back to FsManagerAvbOps.
+    avb_ops_.user_data = this;
 }
 
-void fs_mgr_dummy_avb_ops_free(AvbOps* ops) { free(ops); }
+AvbIOResult FsManagerAvbOps::ReadFromPartition(const char* partition, int64_t offset,
+                                               size_t num_bytes, void* buffer,
+                                               size_t* out_num_read) {
+    // Appends |partition| to the device_file_by_name_prefix_, e.g.,
+    //    - /dev/block/platform/soc.0/7824900.sdhci/by-name/ ->
+    //    - /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a
+    std::string path = device_file_by_name_prefix_ + partition;
+
+    // Ensures the device path (a symlink created by init) is ready to
+    // access. fs_mgr_test_access() will test a few iterations if the
+    // path doesn't exist yet.
+    if (fs_mgr_test_access(path.c_str()) < 0) {
+        return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
+    }
+
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
+    if (fd < 0) {
+        PERROR << "Failed to open " << path.c_str();
+        return AVB_IO_RESULT_ERROR_IO;
+    }
+
+    // If offset is negative, interprets its absolute value as the
+    //  number of bytes from the end of the partition.
+    if (offset < 0) {
+        off64_t total_size = lseek64(fd, 0, SEEK_END);
+        if (total_size == -1) {
+            LERROR << "Failed to lseek64 to end of the partition";
+            return AVB_IO_RESULT_ERROR_IO;
+        }
+        offset = total_size + offset;
+        // Repositions the offset to the beginning.
+        if (lseek64(fd, 0, SEEK_SET) == -1) {
+            LERROR << "Failed to lseek64 to the beginning of the partition";
+            return AVB_IO_RESULT_ERROR_IO;
+        }
+    }
+
+    // On Linux, we never get partial reads from block devices (except
+    // for EOF).
+    ssize_t num_read = TEMP_FAILURE_RETRY(pread64(fd, buffer, num_bytes, offset));
+    if (num_read < 0 || (size_t)num_read != num_bytes) {
+        PERROR << "Failed to read " << num_bytes << " bytes from " << path.c_str() << " offset "
+               << offset;
+        return AVB_IO_RESULT_ERROR_IO;
+    }
+
+    if (out_num_read != nullptr) {
+        *out_num_read = num_read;
+    }
+
+    return AVB_IO_RESULT_OK;
+}
+
+AvbSlotVerifyResult FsManagerAvbOps::AvbSlotVerify(const std::string& ab_suffix,
+                                                   bool allow_verification_error,
+                                                   AvbSlotVerifyData** out_data) {
+    // Invokes avb_slot_verify() to load and verify all vbmeta images.
+    // Sets requested_partitions to nullptr as it's to copy the contents
+    // of HASH partitions into handle>avb_slot_data_, which is not required as
+    // fs_mgr only deals with HASHTREE partitions.
+    const char* requested_partitions[] = {nullptr};
+    return avb_slot_verify(&avb_ops_, requested_partitions, ab_suffix.c_str(),
+                           allow_verification_error, out_data);
+}
diff --git a/fs_mgr/fs_mgr_avb_ops.h b/fs_mgr/fs_mgr_avb_ops.h
index bfdec9a..ec4a8c9 100644
--- a/fs_mgr/fs_mgr_avb_ops.h
+++ b/fs_mgr/fs_mgr_avb_ops.h
@@ -29,31 +29,34 @@
 
 #include "fs_mgr.h"
 
-__BEGIN_DECLS
+// This class provides C++ bindings to interact with libavb, a small
+// self-contained piece of code that's intended to be used in bootloaders.
+// It mainly contains two functions:
+//   - ReadFromPartition(): to read AVB metadata from a given partition.
+//     It provides the implementation of AvbOps.read_from_partition() when
+//     reading metadata through libavb.
+//   - AvbSlotVerify(): the C++ binding of libavb->avb_slot_verify() to
+//     read and verify the metadata and store it into the out_data parameter.
+//     The caller MUST check the integrity of metadata against the
+//     androidboot.vbmeta.{hash_alg, size, digest} values from /proc/cmdline.
+//     e.g., see class FsManagerAvbVerifier for more details.
+//
+class FsManagerAvbOps {
+  public:
+    FsManagerAvbOps(const std::string& device_file_by_name_prefix);
 
-/* Allocates a "dummy" AvbOps instance solely for use in user-space.
- * Returns nullptr on OOM.
- *
- * It mainly provides read_from_partitions() for user-space to get
- * AvbSlotVerifyData.vbmeta_images[] and the caller MUST check their
- * integrity against the androidboot.vbmeta.{hash_alg, size, digest}
- * values from /proc/cmdline, e.g. verify_vbmeta_images()
- * in fs_mgr_avb.cpp.
- *
- * Other I/O operations are only required in boot loader so we set
- * them as dummy operations here.
- *  - Will allow any public key for signing.
- *  - returns 0 for any rollback index location.
- *  - returns device is unlocked regardless of the actual state.
- *  - returns a dummy guid for any partition.
- *
- * Frees with fs_mgr_dummy_avb_ops_free().
- */
-AvbOps* fs_mgr_dummy_avb_ops_new(struct fstab* fstab);
+    static FsManagerAvbOps* GetInstanceFromAvbOps(AvbOps* ops) {
+        return reinterpret_cast<FsManagerAvbOps*>(ops->user_data);
+    }
 
-/* Frees an AvbOps instance previously allocated with fs_mgr_avb_ops_new(). */
-void fs_mgr_dummy_avb_ops_free(AvbOps* ops);
+    AvbIOResult ReadFromPartition(const char* partition, int64_t offset, size_t num_bytes,
+                                  void* buffer, size_t* out_num_read);
 
-__END_DECLS
+    AvbSlotVerifyResult AvbSlotVerify(const std::string& ab_suffix, bool allow_verification_error,
+                                      AvbSlotVerifyData** out_data);
 
+  private:
+    AvbOps avb_ops_;
+    std::string device_file_by_name_prefix_;
+};
 #endif /* __CORE_FS_MGR_AVB_OPS_H */
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 0406efd..dfbde18 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -526,7 +526,7 @@
         cnt++;
     }
     /* If an A/B partition, modify block device to be the real block device */
-    if (fs_mgr_update_for_slotselect(fstab) != 0) {
+    if (!fs_mgr_update_for_slotselect(fstab)) {
         LERROR << "Error updating for slotselect";
         goto err;
     }
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 377d2ec..dedffd8 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -41,8 +41,6 @@
 #define PWARNING PLOG(WARNING) << FS_MGR_TAG
 #define PERROR   PLOG(ERROR) << FS_MGR_TAG
 
-__BEGIN_DECLS
-
 #define CRYPTO_TMPFS_OPTIONS "size=256m,mode=0771,uid=1000,gid=1000"
 
 #define WAIT_TIMEOUT 20
@@ -114,10 +112,8 @@
 
 int fs_mgr_set_blk_ro(const char *blockdev);
 int fs_mgr_test_access(const char *device);
-int fs_mgr_update_for_slotselect(struct fstab *fstab);
+bool fs_mgr_update_for_slotselect(struct fstab *fstab);
 bool is_dt_compatible();
 bool is_device_secure();
 
-__END_DECLS
-
 #endif /* __CORE_FS_MGR_PRIV_H */
diff --git a/fs_mgr/fs_mgr_priv_avb.h b/fs_mgr/fs_mgr_priv_avb.h
index dce9f61..99a033e 100644
--- a/fs_mgr/fs_mgr_priv_avb.h
+++ b/fs_mgr/fs_mgr_priv_avb.h
@@ -17,40 +17,77 @@
 #ifndef __CORE_FS_MGR_PRIV_AVB_H
 #define __CORE_FS_MGR_PRIV_AVB_H
 
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
+#include <memory>
+#include <string>
+
+#include <libavb/libavb.h>
 
 #include "fs_mgr.h"
 
-__BEGIN_DECLS
+enum FsManagerAvbHandleStatus {
+    kFsManagerAvbHandleSuccess = 0,
+    kFsManagerAvbHandleHashtreeDisabled = 1,
+    kFsManagerAvbHandleFail = 2,
+};
 
-#define FS_MGR_SETUP_AVB_HASHTREE_DISABLED (-2)
-#define FS_MGR_SETUP_AVB_FAIL (-1)
-#define FS_MGR_SETUP_AVB_SUCCESS 0
+class FsManagerAvbHandle;
+using FsManagerAvbUniquePtr = std::unique_ptr<FsManagerAvbHandle>;
 
-bool fs_mgr_is_avb_used();
+// Provides a factory method to return a unique_ptr pointing to itself and the
+// SetUpAvb() function to extract dm-verity parameters from AVB metadata to
+// load verity table into kernel through ioctl.
+class FsManagerAvbHandle {
+  public:
+    // The factory method to return a FsManagerAvbUniquePtr that holds
+    // the verified AVB (external/avb) metadata of all verified partitions
+    // in avb_slot_data_.vbmeta_images[].
+    //
+    // The metadata is checked against the following values from /proc/cmdline.
+    //   - androidboot.vbmeta.{hash_alg, size, digest}.
+    //
+    // A typical usage will be:
+    //   - FsManagerAvbUniquePtr handle = FsManagerAvbHandle::Open();
+    //
+    // Possible return values:
+    //   - nullptr: any error when reading and verifying the metadata,
+    //     e.g., I/O error, digest value mismatch, size mismatch, etc.
+    //
+    //   - a valid unique_ptr with status kFsMgrAvbHandleHashtreeDisabled:
+    //     to support the existing 'adb disable-verity' feature in Android.
+    //     It's very helpful for developers to make the filesystem writable to
+    //     allow replacing binaries on the device.
+    //
+    //   - a valid unique_ptr with status kFsMgrAvbHandleSuccess: the metadata
+    //     is verified and can be trusted.
+    //
+    static FsManagerAvbUniquePtr Open(const std::string& device_file_by_name_prefix);
 
-/* Gets AVB metadata through external/avb/libavb for all partitions:
- * AvbSlotVerifyData.vbmeta_images[] and checks their integrity
- * against the androidboot.vbmeta.{hash_alg, size, digest} values
- * from /proc/cmdline.
- *
- * Return values:
- *   - FS_MGR_SETUP_AVB_SUCCESS: the metadata cab be trusted.
- *   - FS_MGR_SETUP_AVB_FAIL: any error when reading and verifying the
- *     metadata, e.g. I/O error, digest value mismatch, size mismatch.
- *   - FS_MGR_SETUP_AVB_HASHTREE_DISABLED: to support the existing
- *     'adb disable-verity' feature in Android. It's very helpful for
- *     developers to make the filesystem writable to allow replacing
- *     binaries on the device.
- */
-int fs_mgr_load_vbmeta_images(struct fstab* fstab);
+    // Sets up dm-verity on the given fstab entry.
+    // Returns true if the mount point is eligible to mount, it includes:
+    //   - status_ is kFsMgrAvbHandleHashtreeDisabled or
+    //   - status_ is kFsMgrAvbHandleSuccess and sending ioctl DM_TABLE_LOAD
+    //     to load verity table is success.
+    // Otherwise, returns false.
+    bool SetUpAvb(fstab_rec* fstab_entry);
 
-void fs_mgr_unload_vbmeta_images();
+    FsManagerAvbHandle(const FsManagerAvbHandle&) = delete; // no copy
+    FsManagerAvbHandle& operator=(const FsManagerAvbHandle&) = delete; // no assignment
 
-int fs_mgr_setup_avb(struct fstab_rec* fstab_entry);
+    FsManagerAvbHandle(FsManagerAvbHandle&&) noexcept = delete;  // no move
+    FsManagerAvbHandle& operator=(FsManagerAvbHandle&&) noexcept = delete; // no move assignment
 
-__END_DECLS
+    ~FsManagerAvbHandle() {
+        if (avb_slot_data_) {
+            avb_slot_verify_data_free(avb_slot_data_);
+        }
+    };
+
+  protected:
+    FsManagerAvbHandle() : avb_slot_data_(nullptr), status_(kFsManagerAvbHandleFail) {}
+
+  private:
+    AvbSlotVerifyData* avb_slot_data_;
+    FsManagerAvbHandleStatus status_;
+};
 
 #endif /* __CORE_FS_MGR_PRIV_AVB_H */
diff --git a/fs_mgr/fs_mgr_priv_sha.h b/fs_mgr/fs_mgr_priv_sha.h
index 882411b..5b53eea 100644
--- a/fs_mgr/fs_mgr_priv_sha.h
+++ b/fs_mgr/fs_mgr_priv_sha.h
@@ -20,16 +20,18 @@
 #include <openssl/sha.h>
 
 class SHA256Hasher {
-   private:
+  private:
     SHA256_CTX sha256_ctx;
     uint8_t hash[SHA256_DIGEST_LENGTH];
 
-   public:
+  public:
     enum { DIGEST_SIZE = SHA256_DIGEST_LENGTH };
 
     SHA256Hasher() { SHA256_Init(&sha256_ctx); }
 
-    void update(const void* data, size_t data_size) { SHA256_Update(&sha256_ctx, data, data_size); }
+    void update(const uint8_t* data, size_t data_size) {
+        SHA256_Update(&sha256_ctx, data, data_size);
+    }
 
     const uint8_t* finalize() {
         SHA256_Final(hash, &sha256_ctx);
@@ -38,11 +40,11 @@
 };
 
 class SHA512Hasher {
-   private:
+  private:
     SHA512_CTX sha512_ctx;
     uint8_t hash[SHA512_DIGEST_LENGTH];
 
-   public:
+  public:
     enum { DIGEST_SIZE = SHA512_DIGEST_LENGTH };
 
     SHA512Hasher() { SHA512_Init(&sha512_ctx); }
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp
index 7a45473..9ca15e2 100644
--- a/fs_mgr/fs_mgr_slotselect.cpp
+++ b/fs_mgr/fs_mgr_slotselect.cpp
@@ -16,37 +16,47 @@
 
 #include <stdio.h>
 
+#include <string>
+
 #include "fs_mgr.h"
 #include "fs_mgr_priv.h"
 
-// Updates |fstab| for slot_suffix. Returns 0 on success, -1 on error.
-int fs_mgr_update_for_slotselect(struct fstab *fstab)
-{
+// Returns "_a" or "_b" based on two possible values in kernel cmdline:
+//   - androidboot.slot = a or b OR
+//   - androidboot.slot_suffix = _a or _b
+// TODO: remove slot_suffix once it's deprecated.
+std::string fs_mgr_get_slot_suffix() {
+    std::string slot;
+    std::string ab_suffix;
+
+    if (fs_mgr_get_boot_config("slot", &slot)) {
+        ab_suffix = "_" + slot;
+    } else if (!fs_mgr_get_boot_config("slot_suffix", &ab_suffix)) {
+        ab_suffix = "";
+    }
+    return ab_suffix;
+}
+
+// Updates |fstab| for slot_suffix. Returns true on success, false on error.
+bool fs_mgr_update_for_slotselect(struct fstab *fstab) {
     int n;
-    int got_suffix = 0;
-    std::string suffix;
+    std::string ab_suffix;
 
     for (n = 0; n < fstab->num_entries; n++) {
         if (fstab->recs[n].fs_mgr_flags & MF_SLOTSELECT) {
             char *tmp;
-
-            if (!got_suffix) {
-                std::string slot;
-                if (fs_mgr_get_boot_config("slot", &slot)) {
-                    suffix = "_" + slot;
-                } else if (!fs_mgr_get_boot_config("slot_suffix", &suffix)) {
-                    // remove slot_suffix once bootloaders update to new androidboot.slot param
-                    return -1;
-                }
+            if (ab_suffix.empty()) {
+                ab_suffix = fs_mgr_get_slot_suffix();
+                // Returns false as non A/B devices should not have MF_SLOTSELECT.
+                if (ab_suffix.empty()) return false;
             }
-
-            if (asprintf(&tmp, "%s%s", fstab->recs[n].blk_device, suffix.c_str()) > 0) {
+            if (asprintf(&tmp, "%s%s", fstab->recs[n].blk_device, ab_suffix.c_str()) > 0) {
                 free(fstab->recs[n].blk_device);
                 fstab->recs[n].blk_device = tmp;
             } else {
-                return -1;
+                return false;
             }
         }
     }
-    return 0;
+    return true;
 }
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 4b626de..3c2fea4 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -22,6 +22,12 @@
 #include <stdbool.h>
 #include <linux/dm-ioctl.h>
 
+// C++ only headers
+// TODO: move this into separate header files under include/fs_mgr/*.h
+#ifdef __cplusplus
+#include <string>
+#endif
+
 // Magic number at start of verity metadata
 #define VERITY_METADATA_MAGIC_NUMBER 0xb001b001
 
@@ -29,9 +35,7 @@
 // turn verity off in userdebug builds.
 #define VERITY_METADATA_MAGIC_DISABLE 0x46464f56 // "VOFF"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+__BEGIN_DECLS
 
 // Verity modes
 enum verity_mode {
@@ -139,8 +143,12 @@
 #define FS_MGR_SETUP_VERITY_SUCCESS 0
 int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev);
 
+__END_DECLS
+
+// C++ only functions
+// TODO: move this into separate header files under include/fs_mgr/*.h
 #ifdef __cplusplus
-}
+std::string fs_mgr_get_slot_suffix();
 #endif
 
 #endif /* __CORE_FS_MGR_H */
diff --git a/include/backtrace b/include/backtrace
new file mode 120000
index 0000000..93ce2b1
--- /dev/null
+++ b/include/backtrace
@@ -0,0 +1 @@
+../libbacktrace/include/backtrace
\ No newline at end of file
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 7298dff..e1d9b94 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -607,7 +607,7 @@
     bool runFsck = false;
     bool commandInvalid = false;
 
-    if (cmd_params.size() > 2) {
+    if (cmd_params.size() > 3) {
         commandInvalid = true;
     } else if (cmd_params[0] == "shutdown") {
         cmd = ANDROID_RB_POWEROFF;
@@ -619,7 +619,7 @@
         }
     } else if (cmd_params[0] == "reboot") {
         cmd = ANDROID_RB_RESTART2;
-        if (cmd_params.size() == 2) {
+        if (cmd_params.size() >= 2) {
             reboot_target = cmd_params[1];
             // When rebooting to the bootloader notify the bootloader writing
             // also the BCB.
@@ -631,6 +631,10 @@
                                << err;
                 }
             }
+            // If there is an additional bootloader parameter, pass it along
+            if (cmd_params.size() == 3) {
+                reboot_target += "," + cmd_params[2];
+            }
         }
     } else if (command == "thermal-shutdown") {  // no additional parameter allowed
         cmd = ANDROID_RB_THERMOFF;
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 8f74a1a..7de72a8 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -55,6 +55,11 @@
     "UnwindPtrace.cpp",
 ]
 
+cc_library_headers {
+    name: "libbacktrace_headers",
+    export_include_dirs: ["include"],
+}
+
 cc_library {
     name: "libbacktrace",
     defaults: ["libbacktrace_common"],
@@ -64,6 +69,8 @@
         "BacktraceMap.cpp",
     ],
 
+    export_include_dirs: ["include"],
+
     target: {
         darwin: {
             enabled: true,
diff --git a/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
similarity index 100%
rename from include/backtrace/Backtrace.h
rename to libbacktrace/include/backtrace/Backtrace.h
diff --git a/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
similarity index 100%
rename from include/backtrace/BacktraceMap.h
rename to libbacktrace/include/backtrace/BacktraceMap.h
diff --git a/include/backtrace/backtrace_constants.h b/libbacktrace/include/backtrace/backtrace_constants.h
similarity index 100%
rename from include/backtrace/backtrace_constants.h
rename to libbacktrace/include/backtrace/backtrace_constants.h
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 2b7412b..b46ad62 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -14,6 +14,7 @@
 
 cc_library_headers {
     name: "libutils_headers",
+    vendor_available: true,
     host_supported: true,
     export_include_dirs: ["include"],
     target: {
@@ -28,6 +29,7 @@
 
 cc_library {
     name: "libutils",
+    vendor_available: true,
     host_supported: true,
 
     srcs: [
diff --git a/logd/main.cpp b/logd/main.cpp
index 946485b..18029eb 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -407,6 +407,11 @@
 // logging plugins like auditd and restart control. Additional
 // transitory per-client threads are created for each reader.
 int main(int argc, char* argv[]) {
+    // logd is written under the assumption that the timezone is UTC.
+    // If TZ is not set, persist.sys.timezone is looked up in some time utility
+    // libc functions, including mktime. It confuses the logd time handling,
+    // so here explicitly set TZ to UTC, which overrides the property.
+    setenv("TZ", "UTC", 1);
     // issue reinit command. KISS argument parsing.
     if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) {
         return issueReinit();
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 3758362..17dade4 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -644,6 +644,12 @@
 on property:sys.boot_completed=1
     bootchart stop
 
+on property:sys.boot_completed=1 && property:ro.build.type=user
+    write /proc/sys/kernel/modules_disabled 1
+
+on property:sys.boot_completed=1 && property:ro.build.type=userdebug
+    write /proc/sys/kernel/modules_disabled 1
+
 # system server cannot write to /proc/sys files,
 # and chown/chmod does not work for /proc/sys/ entries.
 # So proxy writes through init.