Merge "crash_dump: properly dump when we can't talk to tombstoned."
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 3f8bc8f..f970e68 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -358,7 +358,7 @@
             "  devices [-l]                             List all connected devices [with\n"
             "                                           device paths].\n"
             "  continue                                 Continue with autoboot.\n"
-            "  reboot [bootloader]                      Reboot device [into bootloader].\n"
+            "  reboot [bootloader|emergency]            Reboot device [into bootloader or emergency mode].\n"
             "  reboot-bootloader                        Reboot device into bootloader.\n"
             "  help                                     Show this help message.\n"
             "\n"
@@ -1397,6 +1397,7 @@
     bool wants_wipe = false;
     bool wants_reboot = false;
     bool wants_reboot_bootloader = false;
+    bool wants_reboot_emergency = false;
     bool skip_reboot = false;
     bool wants_set_active = false;
     bool skip_secondary = false;
@@ -1648,6 +1649,11 @@
                     wants_reboot_bootloader = true;
                     skip(1);
                 }
+                if (!strcmp(*argv, "emergency")) {
+                    wants_reboot = false;
+                    wants_reboot_emergency = true;
+                    skip(1);
+                }
             }
             require(0);
         } else if(!strcmp(*argv, "reboot-bootloader")) {
@@ -1807,6 +1813,9 @@
     } else if (wants_reboot_bootloader) {
         fb_queue_command("reboot-bootloader", "rebooting into bootloader");
         fb_queue_wait_for_disconnect();
+    } else if (wants_reboot_emergency) {
+        fb_queue_command("reboot-emergency", "rebooting into emergency download (EDL) mode");
+        fb_queue_wait_for_disconnect();
     }
 
     return fb_execute_queue(transport) ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 8d5b51b..e321c17 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -11,7 +11,8 @@
     libcrypto \
     libext4_utils \
     libsquashfs_utils \
-    libselinux
+    libselinux \
+    libavb
 
 include $(CLEAR_VARS)
 LOCAL_CLANG := true
@@ -22,7 +23,9 @@
     fs_mgr_format.c \
     fs_mgr_fstab.c \
     fs_mgr_slotselect.c \
-    fs_mgr_verity.cpp
+    fs_mgr_verity.cpp \
+    fs_mgr_avb.cpp \
+    fs_mgr_avb_ops.cpp
 LOCAL_C_INCLUDES := \
     $(LOCAL_PATH)/include \
     system/vold \
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index e699b71..43fb9ea 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -46,6 +46,7 @@
 #include <private/android_logger.h>
 
 #include "fs_mgr_priv.h"
+#include "fs_mgr_priv_avb.h"
 #include "fs_mgr_priv_verity.h"
 
 #define KEY_LOC_PROP   "ro.crypto.keyfile.userdata"
@@ -670,11 +671,17 @@
     int mret = -1;
     int mount_errno = 0;
     int attempted_idx = -1;
+    int avb_ret = FS_MGR_SETUP_AVB_FAIL;
 
     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)) ||
@@ -713,7 +720,22 @@
             wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
         }
 
-        if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
+        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) {
+                INFO("AVB HASHTREE disabled\n");
+            } else if (fs_mgr_setup_avb(&fstab->recs[i]) !=
+                       FS_MGR_SETUP_AVB_SUCCESS) {
+                ERROR("Failed to set up AVB on partition: %s, skipping!\n",
+                      fstab->recs[i].mount_point);
+                /* Skips mounting the device. */
+                continue;
+            }
+        } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
             int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
             if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
                 INFO("Verity disabled");
@@ -722,6 +744,7 @@
                 continue;
             }
         }
+
         int last_idx_inspected;
         int top_idx = i;
 
@@ -825,6 +848,10 @@
         }
     }
 
+    if (fs_mgr_is_avb_used()) {
+        fs_mgr_unload_vbmeta_images();
+    }
+
     if (error_count) {
         return -1;
     } else {
@@ -845,11 +872,17 @@
     int mount_errors = 0;
     int first_mount_errno = 0;
     char *m;
+    int avb_ret = FS_MGR_SETUP_AVB_FAIL;
 
     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;
@@ -882,7 +915,22 @@
             do_reserved_size(n_blk_device, fstab->recs[i].fs_type, &fstab->recs[i]);
         }
 
-        if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
+        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) {
+                INFO("AVB HASHTREE disabled\n");
+            } else if (fs_mgr_setup_avb(&fstab->recs[i]) !=
+                       FS_MGR_SETUP_AVB_SUCCESS) {
+                ERROR("Failed to set up AVB on partition: %s, skipping!\n",
+                      fstab->recs[i].mount_point);
+                /* Skips mounting the device. */
+                continue;
+            }
+        } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
             int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
             if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
                 INFO("Verity disabled");
@@ -921,6 +969,9 @@
     }
 
 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
new file mode 100644
index 0000000..51632cf
--- /dev/null
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -0,0 +1,642 @@
+/*
+ * Copyright (C) 2016 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 <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <cutils/properties.h>
+#include <libavb/libavb.h>
+#include <openssl/sha.h>
+#include <sys/ioctl.h>
+#include <utils/Compat.h>
+
+#include "fs_mgr.h"
+#include "fs_mgr_avb_ops.h"
+#include "fs_mgr_priv.h"
+#include "fs_mgr_priv_avb.h"
+#include "fs_mgr_priv_dm_ioctl.h"
+#include "fs_mgr_priv_sha.h"
+
+/* The format of dm-verity construction parameters:
+ *     <version> <dev> <hash_dev> <data_block_size> <hash_block_size>
+ *     <num_data_blocks> <hash_start_block> <algorithm> <digest> <salt>
+ */
+#define VERITY_TABLE_FORMAT \
+    "%u %s %s %u %u "       \
+    "%" PRIu64 " %" PRIu64 " %s %s %s "
+
+#define VERITY_TABLE_PARAMS(hashtree_desc, blk_device, digest, salt)  \
+    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, /* num_data_blocks. */     \
+        hashtree_desc.tree_offset /                                   \
+            hashtree_desc.hash_block_size, /* hash_start_block. */    \
+        (char *)hashtree_desc.hash_algorithm, digest, salt
+
+#define VERITY_TABLE_OPT_RESTART "restart_on_corruption"
+#define VERITY_TABLE_OPT_IGNZERO "ignore_zero_blocks"
+
+/* The default format of dm-verity optional parameters:
+ *     <#opt_params> ignore_zero_blocks restart_on_corruption
+ */
+#define VERITY_TABLE_OPT_DEFAULT_FORMAT "2 %s %s"
+#define VERITY_TABLE_OPT_DEFAULT_PARAMS \
+    VERITY_TABLE_OPT_IGNZERO, VERITY_TABLE_OPT_RESTART
+
+/* The FEC (forward error correction) format of dm-verity optional parameters:
+ *     <#opt_params> use_fec_from_device <fec_dev>
+ *     fec_roots <num> fec_blocks <num> fec_start <offset>
+ *     ignore_zero_blocks restart_on_corruption
+ */
+#define VERITY_TABLE_OPT_FEC_FORMAT                              \
+    "10 use_fec_from_device %s fec_roots %u fec_blocks %" PRIu64 \
+    " fec_start %" PRIu64 " %s %s"
+
+/* Note that fec_blocks is the size that FEC covers, *not* the
+ * size of the FEC data. Since we use FEC for everything up until
+ * the FEC data, it's the same as the offset (fec_start).
+ */
+#define VERITY_TABLE_OPT_FEC_PARAMS(hashtree_desc, blk_device) \
+    blk_device, hashtree_desc.fec_num_roots,                   \
+        hashtree_desc.fec_offset /                             \
+            hashtree_desc.data_block_size, /* fec_blocks */    \
+        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);
+
+    switch (c) {
+        case '0' ... '9':
+            *value = c - '0';
+            break;
+        case 'a' ... 'f':
+            *value = c - 'a' + 10;
+            break;
+        case 'A' ... 'F':
+            *value = c - 'A' + 10;
+            break;
+        default:
+            return false;
+    }
+
+    return true;
+}
+
+static bool hex_to_bytes(uint8_t *bytes,
+                         size_t bytes_len,
+                         const std::string &hex)
+{
+    FS_MGR_CHECK(bytes != nullptr);
+
+    if (hex.size() % 2 != 0) {
+        return false;
+    }
+    if (hex.size() / 2 > bytes_len) {
+        return false;
+    }
+    for (size_t i = 0, j = 0, n = hex.size(); i < n; i += 2, ++j) {
+        uint8_t high;
+        if (!nibble_value(hex[i], &high)) {
+            return false;
+        }
+        uint8_t low;
+        if (!nibble_value(hex[i + 1], &low)) {
+            return false;
+        }
+        bytes[j] = (high << 4) | low;
+    }
+    return true;
+}
+
+static std::string bytes_to_hex(const uint8_t *bytes, size_t bytes_len)
+{
+    FS_MGR_CHECK(bytes != nullptr);
+
+    static const char *hex_digits = "0123456789abcdef";
+    std::string hex;
+
+    for (size_t i = 0; i < bytes_len; i++) {
+        hex.push_back(hex_digits[(bytes[i] & 0xF0) >> 4]);
+        hex.push_back(hex_digits[bytes[i] & 0x0F]);
+    }
+    return hex;
+}
+
+static bool load_vbmeta_prop(androidboot_vbmeta *vbmeta_prop)
+{
+    FS_MGR_CHECK(vbmeta_prop != nullptr);
+
+    std::string cmdline;
+    android::base::ReadFileToString("/proc/cmdline", &cmdline);
+
+    std::string hash_alg;
+    std::string digest;
+
+    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");
+        } 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;
+            }
+        } else if (key == "androidboot.vbmeta.digest") {
+            digest = value;
+        }
+    }
+
+    // Reads hash algorithm.
+    size_t expected_digest_size = 0;
+    if (hash_alg == "sha256") {
+        expected_digest_size = SHA256_DIGEST_LENGTH * 2;
+        vbmeta_prop->hash_alg = kSHA256;
+    } else if (hash_alg == "sha512") {
+        expected_digest_size = SHA512_DIGEST_LENGTH * 2;
+        vbmeta_prop->hash_alg = kSHA512;
+    } else {
+        ERROR("Unknown hash algorithm: %s\n", hash_alg.c_str());
+        return false;
+    }
+
+    // Reads digest.
+    if (digest.size() != expected_digest_size) {
+        ERROR("Unexpected digest size: %zu (expected %zu)\n", digest.size(),
+              expected_digest_size);
+        return false;
+    }
+
+    if (!hex_to_bytes(vbmeta_prop->digest, sizeof(vbmeta_prop->digest),
+                      digest)) {
+        ERROR("Hash digest contains non-hexidecimal character: %s\n",
+              digest.c_str());
+        return false;
+    }
+
+    return true;
+}
+
+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)
+{
+    if (verify_data.num_vbmeta_images == 0) {
+        ERROR("No vbmeta images\n");
+        return false;
+    }
+
+    size_t total_size = 0;
+    bool digest_matched = false;
+
+    if (vbmeta_prop.hash_alg == kSHA256) {
+        std::tie(total_size, digest_matched) =
+            verify_vbmeta_digest<SHA256Hasher>(verify_data, vbmeta_prop);
+    } else if (vbmeta_prop.hash_alg == kSHA512) {
+        std::tie(total_size, digest_matched) =
+            verify_vbmeta_digest<SHA512Hasher>(verify_data, vbmeta_prop);
+    }
+
+    if (total_size != vbmeta_prop.vbmeta_size) {
+        ERROR("total vbmeta size mismatch: %zu (expected: %zu)\n", total_size,
+              vbmeta_prop.vbmeta_size);
+        return false;
+    }
+
+    if (!digest_matched) {
+        ERROR("vbmeta digest mismatch\n");
+        return false;
+    }
+
+    return true;
+}
+
+static bool hashtree_load_verity_table(
+    struct dm_ioctl *io,
+    const std::string &dm_device_name,
+    int fd,
+    const std::string &blk_device,
+    const AvbHashtreeDescriptor &hashtree_desc,
+    const std::string &salt,
+    const std::string &root_digest)
+{
+    fs_mgr_verity_ioctl_init(io, dm_device_name, DM_STATUS_TABLE_FLAG);
+
+    // The buffer consists of [dm_ioctl][dm_target_spec][verity_params].
+    char *buffer = (char *)io;
+
+    // Builds the dm_target_spec arguments.
+    struct dm_target_spec *dm_target =
+        (struct dm_target_spec *)&buffer[sizeof(struct dm_ioctl)];
+    io->target_count = 1;
+    dm_target->status = 0;
+    dm_target->sector_start = 0;
+    dm_target->length = hashtree_desc.image_size / 512;
+    strcpy(dm_target->target_type, "verity");
+
+    // Builds the verity params.
+    char *verity_params =
+        buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
+    size_t bufsize = DM_BUF_SIZE - (verity_params - buffer);
+
+    int res = 0;
+    if (hashtree_desc.fec_size > 0) {
+        res = snprintf(
+            verity_params, bufsize,
+            VERITY_TABLE_FORMAT VERITY_TABLE_OPT_FEC_FORMAT,
+            VERITY_TABLE_PARAMS(hashtree_desc, blk_device.c_str(),
+                                root_digest.c_str(), salt.c_str()),
+            VERITY_TABLE_OPT_FEC_PARAMS(hashtree_desc, blk_device.c_str()));
+    } else {
+        res = snprintf(verity_params, bufsize,
+                       VERITY_TABLE_FORMAT VERITY_TABLE_OPT_DEFAULT_FORMAT,
+                       VERITY_TABLE_PARAMS(hashtree_desc, blk_device.c_str(),
+                                           root_digest.c_str(), salt.c_str()),
+                       VERITY_TABLE_OPT_DEFAULT_PARAMS);
+    }
+
+    if (res < 0 || (size_t)res >= bufsize) {
+        ERROR("Error building verity table; insufficient buffer size?\n");
+        return false;
+    }
+
+    INFO("loading verity table: '%s'", verity_params);
+
+    // Sets ext target boundary.
+    verity_params += strlen(verity_params) + 1;
+    verity_params = (char *)(((unsigned long)verity_params + 7) & ~7);
+    dm_target->next = verity_params - buffer;
+
+    // Sends the ioctl to load the verity table.
+    if (ioctl(fd, DM_TABLE_LOAD, io)) {
+        ERROR("Error loading verity table (%s)\n", strerror(errno));
+        return false;
+    }
+
+    return true;
+}
+
+static bool hashtree_dm_verity_setup(struct fstab_rec *fstab_entry,
+                                     const AvbHashtreeDescriptor &hashtree_desc,
+                                     const std::string &salt,
+                                     const std::string &root_digest)
+{
+    // Gets the device mapper fd.
+    android::base::unique_fd fd(open("/dev/device-mapper", O_RDWR));
+    if (fd < 0) {
+        ERROR("Error opening device mapper (%s)\n", strerror(errno));
+        return false;
+    }
+
+    // Creates the device.
+    alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
+    struct dm_ioctl *io = (struct dm_ioctl *)buffer;
+    const std::string mount_point(basename(fstab_entry->mount_point));
+    if (!fs_mgr_create_verity_device(io, mount_point, fd)) {
+        ERROR("Couldn't create verity device!\n");
+        return false;
+    }
+
+    // Gets the name of the device file.
+    std::string verity_blk_name;
+    if (!fs_mgr_get_verity_device_name(io, mount_point, fd, &verity_blk_name)) {
+        ERROR("Couldn't get verity device number!\n");
+        return false;
+    }
+
+    // Loads the verity mapping table.
+    if (!hashtree_load_verity_table(io, mount_point, fd,
+                                    std::string(fstab_entry->blk_device),
+                                    hashtree_desc, salt, root_digest)) {
+        ERROR("Couldn't load verity table!\n");
+        return false;
+    }
+
+    // Activates the device.
+    if (!fs_mgr_resume_verity_table(io, mount_point, fd)) {
+        return false;
+    }
+
+    // Marks the underlying block device as read-only.
+    fs_mgr_set_blk_ro(fstab_entry->blk_device);
+
+    // TODO(bowgotsai): support verified all partition at boot.
+    // Updates fstab_rec->blk_device to verity device name.
+    free(fstab_entry->blk_device);
+    fstab_entry->blk_device = strdup(verity_blk_name.c_str());
+
+    // Makes sure we've set everything up properly.
+    if (fs_mgr_test_access(verity_blk_name.c_str()) < 0) {
+        return false;
+    }
+
+    return true;
+}
+
+static bool get_hashtree_descriptor(const std::string &partition_name,
+                                    const AvbSlotVerifyData &verify_data,
+                                    AvbHashtreeDescriptor *out_hashtree_desc,
+                                    std::string *out_salt,
+                                    std::string *out_digest)
+{
+    bool found = false;
+    const uint8_t *desc_partition_name;
+
+    for (size_t i = 0; i < verify_data.num_vbmeta_images && !found; i++) {
+        // Get descriptors from vbmeta_images[i].
+        size_t num_descriptors;
+        std::unique_ptr<const AvbDescriptor *[], decltype(&avb_free)>
+            descriptors(
+                avb_descriptor_get_all(verify_data.vbmeta_images[i].vbmeta_data,
+                                       verify_data.vbmeta_images[i].vbmeta_size,
+                                       &num_descriptors),
+                avb_free);
+
+        if (!descriptors || num_descriptors < 1) {
+            continue;
+        }
+
+        // Ensures that hashtree descriptor is either in /vbmeta or in
+        // the same partition for verity setup.
+        std::string vbmeta_partition_name(
+            verify_data.vbmeta_images[i].partition_name);
+        if (vbmeta_partition_name != "vbmeta" &&
+            vbmeta_partition_name != partition_name) {
+            WARNING("Skip vbmeta image at %s for partition: %s\n",
+                    verify_data.vbmeta_images[i].partition_name,
+                    partition_name.c_str());
+            continue;
+        }
+
+        for (size_t j = 0; j < num_descriptors && !found; j++) {
+            AvbDescriptor desc;
+            if (!avb_descriptor_validate_and_byteswap(descriptors[j], &desc)) {
+                WARNING("Descriptor is invalid.\n");
+                continue;
+            }
+            if (desc.tag == AVB_DESCRIPTOR_TAG_HASHTREE) {
+                desc_partition_name = (const uint8_t *)descriptors[j] +
+                                      sizeof(AvbHashtreeDescriptor);
+                if (!avb_hashtree_descriptor_validate_and_byteswap(
+                        (AvbHashtreeDescriptor *)descriptors[j],
+                        out_hashtree_desc)) {
+                    continue;
+                }
+                if (out_hashtree_desc->partition_name_len !=
+                    partition_name.length()) {
+                    continue;
+                }
+                // Notes that desc_partition_name is not NUL-terminated.
+                std::string hashtree_partition_name(
+                    (const char *)desc_partition_name,
+                    out_hashtree_desc->partition_name_len);
+                if (hashtree_partition_name == partition_name) {
+                    found = true;
+                }
+            }
+        }
+    }
+
+    if (!found) {
+        ERROR("Partition descriptor not found: %s\n", partition_name.c_str());
+        return false;
+    }
+
+    const uint8_t *desc_salt =
+        desc_partition_name + out_hashtree_desc->partition_name_len;
+    *out_salt = bytes_to_hex(desc_salt, out_hashtree_desc->salt_len);
+
+    const uint8_t *desc_digest = desc_salt + out_hashtree_desc->salt_len;
+    *out_digest = bytes_to_hex(desc_digest, out_hashtree_desc->root_digest_len);
+
+    return true;
+}
+
+static inline bool polling_vbmeta_blk_device(struct fstab *fstab)
+{
+    // It needs the block device symlink: fstab_rec->blk_device to read
+    // /vbmeta partition. However, the symlink created by ueventd might
+    // not be ready at this point. Use test_access() to poll it before
+    // trying to read the partition.
+    struct fstab_rec *fstab_entry =
+        fs_mgr_get_entry_for_mount_point(fstab, "/vbmeta");
+
+    // Makes sure /vbmeta block device is ready to access.
+    if (fs_mgr_test_access(fstab_entry->blk_device) < 0) {
+        return false;
+    }
+    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. They will then be imported by init
+    // process to system properties: ro.boot.vbmeta.{hash_alg, size, digest}.
+    //
+    // 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 =
+        android::base::GetProperty("ro.boot.vbmeta.hash_alg", "");
+
+    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);
+
+    if (!polling_vbmeta_blk_device(fstab)) {
+        ERROR("Failed to find block device of /vbmeta\n");
+        return FS_MGR_SETUP_AVB_FAIL;
+    }
+
+    // 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;
+    }
+
+    fs_mgr_avb_ops = fs_mgr_dummy_avb_ops_new(fstab);
+    if (fs_mgr_avb_ops == nullptr) {
+        ERROR("Failed to allocate dummy avb_ops\n");
+        return FS_MGR_SETUP_AVB_FAIL;
+    }
+
+    // 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};
+    const char *ab_suffix =
+        android::base::GetProperty("ro.boot.slot_suffix", "").c_str();
+    AvbSlotVerifyResult verify_result = avb_slot_verify(
+        fs_mgr_avb_ops, requested_partitions, ab_suffix,
+        fs_mgr_vbmeta_prop.allow_verification_error, &fs_mgr_avb_verify_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) {
+            ERROR("ERROR_VERIFICATION isn't allowed\n");
+            goto fail;
+        }
+    } else if (verify_result != AVB_SLOT_VERIFY_RESULT_OK) {
+        ERROR("avb_slot_verify failed, result: %d\n", verify_result);
+        goto fail;
+    }
+
+    // Verifies vbmeta images against the digest passed from bootloader.
+    if (!verify_vbmeta_images(*fs_mgr_avb_verify_data, fs_mgr_vbmeta_prop)) {
+        ERROR("verify_vbmeta_images failed\n");
+        goto fail;
+    } 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,
+            &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;
+        }
+    }
+
+    if (verify_result == AVB_SLOT_VERIFY_RESULT_OK) {
+        return FS_MGR_SETUP_AVB_SUCCESS;
+    }
+
+fail:
+    fs_mgr_unload_vbmeta_images();
+    return FS_MGR_SETUP_AVB_FAIL;
+}
+
+void fs_mgr_unload_vbmeta_images()
+{
+    if (fs_mgr_avb_verify_data != nullptr) {
+        avb_slot_verify_data_free(fs_mgr_avb_verify_data);
+    }
+
+    if (fs_mgr_avb_ops != nullptr) {
+        fs_mgr_dummy_avb_ops_free(fs_mgr_avb_ops);
+    }
+}
+
+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;
+    }
+
+    std::string partition_name(basename(fstab_entry->mount_point));
+    if (!avb_validate_utf8((const uint8_t *)partition_name.c_str(),
+                           partition_name.length())) {
+        ERROR("Partition name: %s is not valid UTF-8.\n",
+              partition_name.c_str());
+        return FS_MGR_SETUP_AVB_FAIL;
+    }
+
+    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;
+    }
+
+    // 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 FS_MGR_SETUP_AVB_SUCCESS;
+}
diff --git a/fs_mgr/fs_mgr_avb_ops.cpp b/fs_mgr/fs_mgr_avb_ops.cpp
new file mode 100644
index 0000000..f3030eb
--- /dev/null
+++ b/fs_mgr/fs_mgr_avb_ops.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <string>
+
+#include <android-base/macros.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <libavb/libavb.h>
+#include <utils/Compat.h>
+
+#include "fs_mgr.h"
+#include "fs_mgr_avb_ops.h"
+#include "fs_mgr_priv.h"
+
+static struct fstab *fs_mgr_fstab = nullptr;
+
+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.
+    //
+    // In AVB, we can assume that there's an entry for the /misc mount
+    // point and use that to get the device file for the misc partition.
+    // From there we'll assume that a by-name scheme is used
+    // so we can just replace the trailing "misc" by the given
+    // |partition|, e.g.
+    //
+    //    - /dev/block/platform/soc.0/7824900.sdhci/by-name/misc ->
+    //    - /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a
+
+    struct fstab_rec *fstab_entry =
+        fs_mgr_get_entry_for_mount_point(fs_mgr_fstab, "/misc");
+
+    if (fstab_entry == nullptr) {
+        ERROR("Partition (%s) not found in fstab\n", partition);
+        return AVB_IO_RESULT_ERROR_IO;
+    }
+
+    std::string partition_name(partition);
+    std::string path(fstab_entry->blk_device);
+    // Replaces the last field of device file if it's not misc.
+    if (!android::base::StartsWith(partition_name, "misc")) {
+        size_t end_slash = path.find_last_of("/");
+        std::string by_name_prefix(path.substr(0, end_slash + 1));
+        path = by_name_prefix + partition_name;
+    }
+
+    android::base::unique_fd fd(
+        TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
+
+    if (fd < 0) {
+        ERROR("Failed to open %s (%s)\n", path.c_str(), strerror(errno));
+        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) {
+            ERROR("Failed to lseek64 to end of the partition\n");
+            return AVB_IO_RESULT_ERROR_IO;
+        }
+        offset = total_size + offset;
+        // Repositions the offset to the beginning.
+        if (lseek64(fd, 0, SEEK_SET) == -1) {
+            ERROR("Failed to lseek64 to the beginning of the partition\n");
+            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) {
+        ERROR("Failed to read %zu bytes from %s offset %" PRId64 " (%s)\n",
+              num_bytes, path.c_str(), offset, strerror(errno));
+        return AVB_IO_RESULT_ERROR_IO;
+    }
+
+    if (out_num_read != nullptr) {
+        *out_num_read = num_read;
+    }
+
+    return AVB_IO_RESULT_OK;
+}
+
+static AvbIOResult dummy_read_rollback_index(AvbOps *ops ATTRIBUTE_UNUSED,
+                                             size_t rollback_index_location
+                                                 ATTRIBUTE_UNUSED,
+                                             uint64_t *out_rollback_index)
+{
+    // rollback_index has been checked in bootloader phase.
+    // In user-space, returns the smallest value 0 to pass the check.
+    *out_rollback_index = 0;
+    return AVB_IO_RESULT_OK;
+}
+
+static AvbIOResult dummy_validate_vbmeta_public_key(
+    AvbOps *ops ATTRIBUTE_UNUSED,
+    const uint8_t *public_key_data ATTRIBUTE_UNUSED,
+    size_t public_key_length ATTRIBUTE_UNUSED,
+    const uint8_t *public_key_metadata ATTRIBUTE_UNUSED,
+    size_t public_key_metadata_length ATTRIBUTE_UNUSED,
+    bool *out_is_trusted)
+{
+    // vbmeta public key has been checked in bootloader phase.
+    // In user-space, returns true to pass the check.
+    //
+    // 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;
+}
+
+static AvbIOResult dummy_read_is_device_unlocked(AvbOps *ops ATTRIBUTE_UNUSED,
+                                                 bool *out_is_unlocked)
+{
+    // The function is for bootloader to update the value into
+    // androidboot.vbmeta.device_state in kernel cmdline.
+    // In user-space, returns true as we don't need to update it anymore.
+    *out_is_unlocked = true;
+    return AVB_IO_RESULT_OK;
+}
+
+static AvbIOResult dummy_get_unique_guid_for_partition(
+    AvbOps *ops ATTRIBUTE_UNUSED,
+    const char *partition ATTRIBUTE_UNUSED,
+    char *guid_buf,
+    size_t guid_buf_size)
+{
+    // The function is for bootloader to set the correct UUID
+    // for a given partition in kernel cmdline.
+    // In user-space, returns a faking one as we don't need to update
+    // it anymore.
+    snprintf(guid_buf, guid_buf_size, "1234-fake-guid-for:%s", partition);
+    return AVB_IO_RESULT_OK;
+}
+
+AvbOps *fs_mgr_dummy_avb_ops_new(struct fstab *fstab)
+{
+    AvbOps *ops;
+
+    // Assigns the fstab to the static variable for later use.
+    fs_mgr_fstab = fstab;
+
+    ops = (AvbOps *)calloc(1, sizeof(AvbOps));
+    if (ops == nullptr) {
+        ERROR("Error allocating memory for AvbOps.\n");
+        return nullptr;
+    }
+
+    // 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;
+}
+
+void fs_mgr_dummy_avb_ops_free(AvbOps *ops)
+{
+    free(ops);
+}
diff --git a/fs_mgr/fs_mgr_avb_ops.h b/fs_mgr/fs_mgr_avb_ops.h
new file mode 100644
index 0000000..9f99be8
--- /dev/null
+++ b/fs_mgr/fs_mgr_avb_ops.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __CORE_FS_MGR_AVB_OPS_H
+#define __CORE_FS_MGR_AVB_OPS_H
+
+#include <libavb/libavb.h>
+
+#include "fs_mgr.h"
+
+__BEGIN_DECLS
+
+/* 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);
+
+/* Frees an AvbOps instance previously allocated with fs_mgr_avb_ops_new(). */
+void fs_mgr_dummy_avb_ops_free(AvbOps *ops);
+
+__END_DECLS
+
+#endif /* __CORE_FS_MGR_AVB_OPS_H */
diff --git a/fs_mgr/fs_mgr_dm_ioctl.cpp b/fs_mgr/fs_mgr_dm_ioctl.cpp
index 75ce621..939657e 100644
--- a/fs_mgr/fs_mgr_dm_ioctl.cpp
+++ b/fs_mgr/fs_mgr_dm_ioctl.cpp
@@ -68,7 +68,7 @@
                                    int fd,
                                    std::string *out_dev_name)
 {
-    CHECK(out_dev_name != nullptr);
+    FS_MGR_CHECK(out_dev_name != nullptr);
 
     fs_mgr_verity_ioctl_init(io, name, 0);
     if (ioctl(fd, DM_DEV_STATUS, io)) {
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index 41fb746..b9d5617 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -35,6 +35,8 @@
     unsigned int zram_size;
     uint64_t reserved_size;
     unsigned int file_encryption_mode;
+    unsigned int erase_blk_size;
+    unsigned int logical_blk_size;
 };
 
 struct flag_list {
@@ -77,6 +79,7 @@
     { "max_comp_streams=",  MF_MAX_COMP_STREAMS },
     { "verifyatboot",       MF_VERIFYATBOOT },
     { "verify",             MF_VERIFY },
+    { "avb",                MF_AVB },
     { "noemulatedsd",       MF_NOEMULATEDSD },
     { "notrim",             MF_NOTRIM },
     { "formattable",        MF_FORMATTABLE },
@@ -85,6 +88,8 @@
     { "latemount",          MF_LATEMOUNT },
     { "reservedsize=",      MF_RESERVEDSIZE },
     { "quota",              MF_QUOTA },
+    { "eraseblk=",          MF_ERASEBLKSIZE },
+    { "logicalblk=",        MF_LOGICALBLKSIZE },
     { "defaults",           0 },
     { 0,                    0 },
 };
@@ -239,6 +244,22 @@
                      * reserved size of the partition.  Get it and return it.
                      */
                     flag_vals->reserved_size = parse_size(strchr(p, '=') + 1);
+                } else if ((fl[i].flag == MF_ERASEBLKSIZE) && flag_vals) {
+                    /* The erase block size flag is followed by an = and the flash
+                     * erase block size. Get it, check that it is a power of 2 and
+                     * at least 4096, and return it.
+                     */
+                    unsigned int val = strtoul(strchr(p, '=') + 1, NULL, 0);
+                    if (val >= 4096 && (val & (val - 1)) == 0)
+                        flag_vals->erase_blk_size = val;
+                } else if ((fl[i].flag == MF_LOGICALBLKSIZE) && flag_vals) {
+                    /* The logical block size flag is followed by an = and the flash
+                     * logical block size. Get it, check that it is a power of 2 and
+                     * at least 4096, and return it.
+                     */
+                    unsigned int val = strtoul(strchr(p, '=') + 1, NULL, 0);
+                    if (val >= 4096 && (val & (val - 1)) == 0)
+                        flag_vals->logical_blk_size = val;
                 }
                 break;
             }
@@ -385,6 +406,8 @@
         fstab->recs[cnt].zram_size = flag_vals.zram_size;
         fstab->recs[cnt].reserved_size = flag_vals.reserved_size;
         fstab->recs[cnt].file_encryption_mode = flag_vals.file_encryption_mode;
+        fstab->recs[cnt].erase_blk_size = flag_vals.erase_blk_size;
+        fstab->recs[cnt].logical_blk_size = flag_vals.logical_blk_size;
         cnt++;
     }
     /* If an A/B partition, modify block device to be the real block device */
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 7f917d9..0a27c7a 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -20,6 +20,17 @@
 #include <cutils/klog.h>
 #include <fs_mgr.h>
 
+#ifdef __cplusplus
+#include <android-base/logging.h>
+/* The CHECK() in logging.h will use program invocation name as the tag.
+ * Thus, the log will have prefix "init: " when libfs_mgr is statically
+ * linked in the init process. This might be opaque when debugging.
+ * Appends "in libfs_mgr" at the end of the abort message to explicitly
+ * indicate the check happens in fs_mgr.
+ */
+#define FS_MGR_CHECK(x) CHECK(x) << "in libfs_mgr "
+#endif
+
 __BEGIN_DECLS
 
 #define INFO(x...)    KLOG_INFO("fs_mgr", x)
@@ -89,6 +100,9 @@
 #define MF_MAX_COMP_STREAMS 0x100000
 #define MF_RESERVEDSIZE     0x200000
 #define MF_QUOTA            0x400000
+#define MF_ERASEBLKSIZE     0x800000
+#define MF_LOGICALBLKSIZE  0X1000000
+#define MF_AVB             0X2000000
 
 #define DM_BUF_SIZE 4096
 
diff --git a/fs_mgr/fs_mgr_priv_avb.h b/fs_mgr/fs_mgr_priv_avb.h
new file mode 100644
index 0000000..6d0171c
--- /dev/null
+++ b/fs_mgr/fs_mgr_priv_avb.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CORE_FS_MGR_PRIV_AVB_H
+#define __CORE_FS_MGR_PRIV_AVB_H
+
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+#include "fs_mgr.h"
+
+__BEGIN_DECLS
+
+#define FS_MGR_SETUP_AVB_HASHTREE_DISABLED (-2)
+#define FS_MGR_SETUP_AVB_FAIL (-1)
+#define FS_MGR_SETUP_AVB_SUCCESS 0
+
+bool fs_mgr_is_avb_used();
+
+/* 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);
+
+void fs_mgr_unload_vbmeta_images();
+
+int fs_mgr_setup_avb(struct fstab_rec *fstab_entry);
+
+__END_DECLS
+
+#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
new file mode 100644
index 0000000..1abc273
--- /dev/null
+++ b/fs_mgr/fs_mgr_priv_sha.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CORE_FS_MGR_PRIV_SHA_H
+#define __CORE_FS_MGR_PRIV_SHA_H
+
+#include <openssl/sha.h>
+
+class SHA256Hasher
+{
+   private:
+    SHA256_CTX sha256_ctx;
+    uint8_t hash[SHA256_DIGEST_LENGTH];
+
+   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);
+    }
+
+    const uint8_t *finalize()
+    {
+        SHA256_Final(hash, &sha256_ctx);
+        return hash;
+    }
+};
+
+class SHA512Hasher
+{
+   private:
+    SHA512_CTX sha512_ctx;
+    uint8_t hash[SHA512_DIGEST_LENGTH];
+
+   public:
+    enum { DIGEST_SIZE = SHA512_DIGEST_LENGTH };
+
+    SHA512Hasher()
+    {
+        SHA512_Init(&sha512_ctx);
+    }
+
+    void update(const uint8_t *data, size_t data_size)
+    {
+        SHA512_Update(&sha512_ctx, data, data_size);
+    }
+
+    const uint8_t *finalize()
+    {
+        SHA512_Final(hash, &sha512_ctx);
+        return hash;
+    }
+};
+
+#endif /* __CORE_FS_MGR_PRIV_SHA_H */
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index ef7fdd3..d959798 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -77,6 +77,8 @@
     unsigned int zram_size;
     uint64_t reserved_size;
     unsigned int file_encryption_mode;
+    unsigned int erase_blk_size;
+    unsigned int logical_blk_size;
 };
 
 // Callback function for verity status
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 36c4664..2f69372 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -30,6 +30,8 @@
 #include <time.h>
 #include <unistd.h>
 
+#include <functional>
+
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
 
@@ -42,6 +44,7 @@
 #include <cutils/misc.h>
 #include <cutils/uevent.h>
 #include <cutils/properties.h>
+#include <minui/minui.h>
 
 #ifdef CHARGER_ENABLE_SUSPEND
 #include <suspend/autosuspend.h>
@@ -49,7 +52,6 @@
 
 #include "animation.h"
 #include "AnimationParser.h"
-#include "minui/minui.h"
 
 #include <healthd/healthd.h>
 
@@ -563,9 +565,8 @@
     }
 }
 
-static int set_key_callback(int code, int value, void *data)
+static int set_key_callback(struct charger *charger, int code, int value)
 {
-    struct charger *charger = (struct charger *)data;
     int64_t now = curr_time_ms();
     int down = !!value;
 
@@ -600,7 +601,7 @@
 {
     if (ev->type != EV_KEY)
         return;
-    set_key_callback(ev->code, ev->value, charger);
+    set_key_callback(charger, ev->code, ev->value);
 }
 
 static void set_next_key_check(struct charger *charger,
@@ -757,9 +758,8 @@
    return (int)timeout;
 }
 
-static int input_callback(int fd, unsigned int epevents, void *data)
+static int input_callback(struct charger *charger, int fd, unsigned int epevents)
 {
-    struct charger *charger = (struct charger *)data;
     struct input_event ev;
     int ret;
 
@@ -836,7 +836,8 @@
 
     LOGW("--------------- STARTING CHARGER MODE ---------------\n");
 
-    ret = ev_init(input_callback, charger);
+    ret = ev_init(std::bind(&input_callback, charger, std::placeholders::_1,
+                            std::placeholders::_2));
     if (!ret) {
         epollfd = ev_get_epollfd();
         healthd_register_event(epollfd, charger_event_handler);
@@ -875,7 +876,8 @@
             anim->frames[i].surface = scale_frames[i];
         }
     }
-    ev_sync_key_state(set_key_callback, charger);
+    ev_sync_key_state(std::bind(&set_key_callback, charger, std::placeholders::_1,
+                                std::placeholders::_2));
 
     charger->next_screen_transition = -1;
     charger->next_key_check = -1;
diff --git a/include/cutils b/include/cutils
deleted file mode 120000
index ac2ed40..0000000
--- a/include/cutils
+++ /dev/null
@@ -1 +0,0 @@
-../libcutils/include/cutils/
\ No newline at end of file
diff --git a/libcutils/include/cutils/android_get_control_file.h b/include/cutils/android_get_control_file.h
similarity index 100%
rename from libcutils/include/cutils/android_get_control_file.h
rename to include/cutils/android_get_control_file.h
diff --git a/libcutils/include/cutils/android_reboot.h b/include/cutils/android_reboot.h
similarity index 100%
rename from libcutils/include/cutils/android_reboot.h
rename to include/cutils/android_reboot.h
diff --git a/libcutils/include/cutils/ashmem.h b/include/cutils/ashmem.h
similarity index 100%
rename from libcutils/include/cutils/ashmem.h
rename to include/cutils/ashmem.h
diff --git a/libcutils/include/cutils/atomic.h b/include/cutils/atomic.h
similarity index 100%
rename from libcutils/include/cutils/atomic.h
rename to include/cutils/atomic.h
diff --git a/libcutils/include/cutils/bitops.h b/include/cutils/bitops.h
similarity index 100%
rename from libcutils/include/cutils/bitops.h
rename to include/cutils/bitops.h
diff --git a/libcutils/include/cutils/compiler.h b/include/cutils/compiler.h
similarity index 100%
rename from libcutils/include/cutils/compiler.h
rename to include/cutils/compiler.h
diff --git a/libcutils/include/cutils/config_utils.h b/include/cutils/config_utils.h
similarity index 100%
rename from libcutils/include/cutils/config_utils.h
rename to include/cutils/config_utils.h
diff --git a/libcutils/include/cutils/fs.h b/include/cutils/fs.h
similarity index 100%
rename from libcutils/include/cutils/fs.h
rename to include/cutils/fs.h
diff --git a/libcutils/include/cutils/hashmap.h b/include/cutils/hashmap.h
similarity index 100%
rename from libcutils/include/cutils/hashmap.h
rename to include/cutils/hashmap.h
diff --git a/libcutils/include/cutils/iosched_policy.h b/include/cutils/iosched_policy.h
similarity index 100%
rename from libcutils/include/cutils/iosched_policy.h
rename to include/cutils/iosched_policy.h
diff --git a/libcutils/include/cutils/jstring.h b/include/cutils/jstring.h
similarity index 100%
rename from libcutils/include/cutils/jstring.h
rename to include/cutils/jstring.h
diff --git a/libcutils/include/cutils/klog.h b/include/cutils/klog.h
similarity index 97%
rename from libcutils/include/cutils/klog.h
rename to include/cutils/klog.h
index e7cd300..5ae6216 100644
--- a/libcutils/include/cutils/klog.h
+++ b/include/cutils/klog.h
@@ -23,7 +23,6 @@
 
 __BEGIN_DECLS
 
-int  klog_get_level(void);
 void klog_set_level(int level);
 
 void klog_write(int level, const char *fmt, ...)
diff --git a/libcutils/include/cutils/list.h b/include/cutils/list.h
similarity index 100%
rename from libcutils/include/cutils/list.h
rename to include/cutils/list.h
diff --git a/libcutils/include/cutils/log.h b/include/cutils/log.h
similarity index 100%
rename from libcutils/include/cutils/log.h
rename to include/cutils/log.h
diff --git a/libcutils/include/cutils/memory.h b/include/cutils/memory.h
similarity index 100%
rename from libcutils/include/cutils/memory.h
rename to include/cutils/memory.h
diff --git a/libcutils/include/cutils/misc.h b/include/cutils/misc.h
similarity index 100%
rename from libcutils/include/cutils/misc.h
rename to include/cutils/misc.h
diff --git a/libcutils/include/cutils/multiuser.h b/include/cutils/multiuser.h
similarity index 100%
rename from libcutils/include/cutils/multiuser.h
rename to include/cutils/multiuser.h
diff --git a/libcutils/include/cutils/native_handle.h b/include/cutils/native_handle.h
similarity index 100%
rename from libcutils/include/cutils/native_handle.h
rename to include/cutils/native_handle.h
diff --git a/libcutils/include/cutils/open_memstream.h b/include/cutils/open_memstream.h
similarity index 100%
rename from libcutils/include/cutils/open_memstream.h
rename to include/cutils/open_memstream.h
diff --git a/libcutils/include/cutils/partition_utils.h b/include/cutils/partition_utils.h
similarity index 100%
rename from libcutils/include/cutils/partition_utils.h
rename to include/cutils/partition_utils.h
diff --git a/libcutils/include/cutils/properties.h b/include/cutils/properties.h
similarity index 100%
rename from libcutils/include/cutils/properties.h
rename to include/cutils/properties.h
diff --git a/libcutils/include/cutils/qtaguid.h b/include/cutils/qtaguid.h
similarity index 100%
rename from libcutils/include/cutils/qtaguid.h
rename to include/cutils/qtaguid.h
diff --git a/libcutils/include/cutils/record_stream.h b/include/cutils/record_stream.h
similarity index 100%
rename from libcutils/include/cutils/record_stream.h
rename to include/cutils/record_stream.h
diff --git a/libcutils/include/cutils/sched_policy.h b/include/cutils/sched_policy.h
similarity index 100%
rename from libcutils/include/cutils/sched_policy.h
rename to include/cutils/sched_policy.h
diff --git a/libcutils/include/cutils/sockets.h b/include/cutils/sockets.h
similarity index 100%
rename from libcutils/include/cutils/sockets.h
rename to include/cutils/sockets.h
diff --git a/libcutils/include/cutils/str_parms.h b/include/cutils/str_parms.h
similarity index 100%
rename from libcutils/include/cutils/str_parms.h
rename to include/cutils/str_parms.h
diff --git a/libcutils/include/cutils/threads.h b/include/cutils/threads.h
similarity index 100%
rename from libcutils/include/cutils/threads.h
rename to include/cutils/threads.h
diff --git a/libcutils/include/cutils/trace.h b/include/cutils/trace.h
similarity index 100%
rename from libcutils/include/cutils/trace.h
rename to include/cutils/trace.h
diff --git a/libcutils/include/cutils/uevent.h b/include/cutils/uevent.h
similarity index 100%
rename from libcutils/include/cutils/uevent.h
rename to include/cutils/uevent.h
diff --git a/include/log b/include/log
deleted file mode 120000
index 714065f..0000000
--- a/include/log
+++ /dev/null
@@ -1 +0,0 @@
-../liblog/include/log
\ No newline at end of file
diff --git a/liblog/include/log/event_tag_map.h b/include/log/event_tag_map.h
similarity index 100%
rename from liblog/include/log/event_tag_map.h
rename to include/log/event_tag_map.h
diff --git a/liblog/include/log/log.h b/include/log/log.h
similarity index 100%
rename from liblog/include/log/log.h
rename to include/log/log.h
diff --git a/liblog/include/log/log_event_list.h b/include/log/log_event_list.h
similarity index 100%
rename from liblog/include/log/log_event_list.h
rename to include/log/log_event_list.h
diff --git a/libcutils/include/cutils/log.h b/include/log/logd.h
similarity index 100%
copy from libcutils/include/cutils/log.h
copy to include/log/logd.h
diff --git a/libcutils/include/cutils/log.h b/include/log/logger.h
similarity index 100%
copy from libcutils/include/cutils/log.h
copy to include/log/logger.h
diff --git a/liblog/include/log/logprint.h b/include/log/logprint.h
similarity index 100%
rename from liblog/include/log/logprint.h
rename to include/log/logprint.h
diff --git a/liblog/include/log/uio.h b/include/log/uio.h
similarity index 100%
rename from liblog/include/log/uio.h
rename to include/log/uio.h
diff --git a/include/private/android_logger.h b/include/private/android_logger.h
deleted file mode 120000
index f187a6d..0000000
--- a/include/private/android_logger.h
+++ /dev/null
@@ -1 +0,0 @@
-../../liblog/include/private/android_logger.h
\ No newline at end of file
diff --git a/liblog/include/private/android_logger.h b/include/private/android_logger.h
similarity index 100%
rename from liblog/include/private/android_logger.h
rename to include/private/android_logger.h
diff --git a/init/Android.mk b/init/Android.mk
index 35e6f4f..759be52 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -107,6 +107,7 @@
     libz \
     libprocessgroup \
     libnl \
+    libavb
 
 # Create symlinks.
 LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 72fcb5b..d323425 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -27,6 +27,7 @@
 #include <sys/poll.h>
 
 #include <memory>
+#include <vector>
 
 #include <cutils/misc.h>
 #include <cutils/sockets.h>
@@ -48,6 +49,7 @@
 
 #include <fs_mgr.h>
 #include <android-base/file.h>
+#include <android-base/strings.h>
 #include "bootimg.h"
 
 #include "property_service.h"
@@ -70,30 +72,30 @@
     }
 }
 
-static int check_mac_perms(const char *name, char *sctx, struct ucred *cr)
-{
-    char *tctx = NULL;
-    int result = 0;
+static bool check_mac_perms(const std::string& name, char* sctx, struct ucred* cr) {
+
+    if (!sctx) {
+      return false;
+    }
+
+    if (!sehandle_prop) {
+      return false;
+    }
+
+    char* tctx = nullptr;
+    if (selabel_lookup(sehandle_prop, &tctx, name.c_str(), 1) != 0) {
+      return false;
+    }
+
     property_audit_data audit_data;
 
-    if (!sctx)
-        goto err;
-
-    if (!sehandle_prop)
-        goto err;
-
-    if (selabel_lookup(sehandle_prop, &tctx, name, 1) != 0)
-        goto err;
-
-    audit_data.name = name;
+    audit_data.name = name.c_str();
     audit_data.cr = cr;
 
-    if (selinux_check_access(sctx, tctx, "property_service", "set", reinterpret_cast<void*>(&audit_data)) == 0)
-        result = 1;
+    bool has_access = (selinux_check_access(sctx, tctx, "property_service", "set", &audit_data) == 0);
 
     freecon(tctx);
- err:
-    return result;
+    return has_access;
 }
 
 static int check_control_mac_perms(const char *name, char *sctx, struct ucred *cr)
@@ -142,11 +144,9 @@
     }
 }
 
-bool is_legal_property_name(const std::string &name)
-{
+bool is_legal_property_name(const std::string& name) {
     size_t namelen = name.size();
 
-    if (namelen >= PROP_NAME_MAX) return false;
     if (namelen < 1) return false;
     if (name[0] == '.') return false;
     if (name[namelen - 1] == '.') return false;
@@ -169,60 +169,219 @@
     return true;
 }
 
-int property_set(const char* name, const char* value) {
-    size_t valuelen = strlen(value);
+uint32_t property_set(const std::string& name, const std::string& value) {
+    size_t valuelen = value.size();
 
     if (!is_legal_property_name(name)) {
         LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: bad name";
-        return -1;
+        return PROP_ERROR_INVALID_NAME;
     }
+
     if (valuelen >= PROP_VALUE_MAX) {
         LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
                    << "value too long";
-        return -1;
+        return PROP_ERROR_INVALID_VALUE;
     }
 
-    if (strcmp("selinux.restorecon_recursive", name) == 0 && valuelen > 0) {
-        if (restorecon(value, SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
+    if (name == "selinux.restorecon_recursive" && valuelen > 0) {
+        if (restorecon(value.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
             LOG(ERROR) << "Failed to restorecon_recursive " << value;
         }
     }
 
-    prop_info* pi = (prop_info*) __system_property_find(name);
+    prop_info* pi = (prop_info*) __system_property_find(name.c_str());
     if (pi != nullptr) {
         // ro.* properties are actually "write-once".
-        if (!strncmp(name, "ro.", 3)) {
+        if (android::base::StartsWith(name, "ro.")) {
             LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
                        << "property already set";
-            return -1;
+            return PROP_ERROR_READ_ONLY_PROPERTY;
         }
 
-        __system_property_update(pi, value, valuelen);
+        __system_property_update(pi, value.c_str(), valuelen);
     } else {
-        int rc = __system_property_add(name, strlen(name), value, valuelen);
+        int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
         if (rc < 0) {
             LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
                        << "__system_property_add failed";
-            return rc;
+            return PROP_ERROR_SET_FAILED;
         }
     }
 
     // Don't write properties to disk until after we have read all default
     // properties to prevent them from being overwritten by default values.
-    if (persistent_properties_loaded && strncmp("persist.", name, strlen("persist.")) == 0) {
-        write_persistent_property(name, value);
+    if (persistent_properties_loaded && android::base::StartsWith(name, "persist.")) {
+        write_persistent_property(name.c_str(), value.c_str());
     }
-    property_changed(name, value);
-    return 0;
+    property_changed(name.c_str(), value.c_str());
+    return PROP_SUCCESS;
 }
 
-static void handle_property_set_fd()
-{
-    prop_msg msg;
-    int r;
-    char * source_ctx = NULL;
+class SocketConnection {
+ public:
+  SocketConnection(int socket, const struct ucred& cred)
+      : socket_(socket), cred_(cred) {}
 
-    int s = accept(property_set_fd, nullptr, nullptr);
+  ~SocketConnection() {
+    close(socket_);
+  }
+
+  bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) {
+    return RecvFully(value, sizeof(*value), timeout_ms);
+  }
+
+  bool RecvChars(char* chars, size_t size, uint32_t* timeout_ms) {
+    return RecvFully(chars, size, timeout_ms);
+  }
+
+  bool RecvString(std::string* value, uint32_t* timeout_ms) {
+    uint32_t len = 0;
+    if (!RecvUint32(&len, timeout_ms)) {
+      return false;
+    }
+
+    if (len == 0) {
+      *value = "";
+      return true;
+    }
+
+    std::vector<char> chars(len);
+    if (!RecvChars(&chars[0], len, timeout_ms)) {
+      return false;
+    }
+
+    *value = std::string(&chars[0], len);
+    return true;
+  }
+
+  bool SendUint32(uint32_t value) {
+    int result = TEMP_FAILURE_RETRY(send(socket_, &value, sizeof(value), 0));
+    return result == sizeof(value);
+  }
+
+  int socket() {
+    return socket_;
+  }
+
+  const struct ucred& cred() {
+    return cred_;
+  }
+
+ private:
+  bool PollIn(uint32_t* timeout_ms) {
+    struct pollfd ufds[1];
+    ufds[0].fd = socket_;
+    ufds[0].events = POLLIN;
+    ufds[0].revents = 0;
+    while (*timeout_ms > 0) {
+      Timer timer;
+      int nr = poll(ufds, 1, *timeout_ms);
+      uint64_t millis = timer.duration_ns()/1000000;
+      *timeout_ms = (millis > *timeout_ms) ? 0 : *timeout_ms - millis;
+
+      if (nr > 0) {
+        return true;
+      }
+
+      if (nr == 0) {
+        // Timeout
+        break;
+      }
+
+      if (nr < 0 && errno != EINTR) {
+        PLOG(ERROR) << "sys_prop: error waiting for uid " << cred_.uid << " to send property message";
+        return false;
+      } else { // errno == EINTR
+        // Timer rounds milliseconds down in case of EINTR we want it to be rounded up
+        // to avoid slowing init down by causing EINTR with under millisecond timeout.
+        if (*timeout_ms > 0) {
+          --(*timeout_ms);
+        }
+      }
+    }
+
+    LOG(ERROR) << "sys_prop: timeout waiting for uid " << cred_.uid << " to send property message.";
+    return false;
+  }
+
+  bool RecvFully(void* data_ptr, size_t size, uint32_t* timeout_ms) {
+    size_t bytes_left = size;
+    char* data = static_cast<char*>(data_ptr);
+    while (*timeout_ms > 0 && bytes_left > 0) {
+      if (!PollIn(timeout_ms)) {
+        return false;
+      }
+
+      int result = TEMP_FAILURE_RETRY(recv(socket_, data, bytes_left, MSG_DONTWAIT));
+      if (result <= 0) {
+        return false;
+      }
+
+      bytes_left -= result;
+      data += result;
+    }
+
+    return bytes_left == 0;
+  }
+
+  int socket_;
+  struct ucred cred_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection);
+};
+
+static void handle_property_set(SocketConnection& socket,
+                                const std::string& name,
+                                const std::string& value,
+                                bool legacy_protocol) {
+  const char* cmd_name = legacy_protocol ? "PROP_MSG_SETPROP" : "PROP_MSG_SETPROP2";
+  if (!is_legal_property_name(name)) {
+    LOG(ERROR) << "sys_prop(" << cmd_name << "): illegal property name \"" << name << "\"";
+    socket.SendUint32(PROP_ERROR_INVALID_NAME);
+    return;
+  }
+
+  struct ucred cr = socket.cred();
+  char* source_ctx = nullptr;
+  getpeercon(socket.socket(), &source_ctx);
+
+  if (android::base::StartsWith(name, "ctl.")) {
+    if (check_control_mac_perms(value.c_str(), source_ctx, &cr)) {
+      handle_control_message(name.c_str() + 4, value.c_str());
+      if (!legacy_protocol) {
+        socket.SendUint32(PROP_SUCCESS);
+      }
+    } else {
+      LOG(ERROR) << "sys_prop(" << cmd_name << "): Unable to " << (name.c_str() + 4)
+                 << " service ctl [" << value << "]"
+                 << " uid:" << cr.uid
+                 << " gid:" << cr.gid
+                 << " pid:" << cr.pid;
+      if (!legacy_protocol) {
+        socket.SendUint32(PROP_ERROR_HANDLE_CONTROL_MESSAGE);
+      }
+    }
+  } else {
+    if (check_mac_perms(name, source_ctx, &cr)) {
+      uint32_t result = property_set(name, value);
+      if (!legacy_protocol) {
+        socket.SendUint32(result);
+      }
+    } else {
+      LOG(ERROR) << "sys_prop(" << cmd_name << "): permission denied uid:" << cr.uid << " name:" << name;
+      if (!legacy_protocol) {
+        socket.SendUint32(PROP_ERROR_PERMISSION_DENIED);
+      }
+    }
+  }
+
+  freecon(source_ctx);
+}
+
+static void handle_property_set_fd() {
+    static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */
+
+    int s = accept4(property_set_fd, nullptr, nullptr, SOCK_CLOEXEC);
     if (s == -1) {
         return;
     }
@@ -236,72 +395,50 @@
         return;
     }
 
-    static constexpr int timeout_ms = 2 * 1000;  /* Default 2 sec timeout for caller to send property. */
-    struct pollfd ufds[1];
-    ufds[0].fd = s;
-    ufds[0].events = POLLIN;
-    ufds[0].revents = 0;
-    int nr = TEMP_FAILURE_RETRY(poll(ufds, 1, timeout_ms));
-    if (nr == 0) {
-        LOG(ERROR) << "sys_prop: timeout waiting for uid " << cr.uid << " to send property message.";
-        close(s);
-        return;
-    } else if (nr < 0) {
-        PLOG(ERROR) << "sys_prop: error waiting for uid " << cr.uid << " to send property message";
-        close(s);
+    SocketConnection socket(s, cr);
+    uint32_t timeout_ms = kDefaultSocketTimeout;
+
+    uint32_t cmd = 0;
+
+    if (!socket.RecvUint32(&cmd, &timeout_ms)) {
+        PLOG(ERROR) << "sys_prop: error while reading command from the socket";
+        socket.SendUint32(PROP_ERROR_READ_CMD);
         return;
     }
 
-    r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT));
-    if(r != sizeof(prop_msg)) {
-        PLOG(ERROR) << "sys_prop: mis-match msg size received: " << r << " expected: " << sizeof(prop_msg);
-        close(s);
-        return;
-    }
+    switch(cmd) {
+    case PROP_MSG_SETPROP: {
+        char prop_name[PROP_NAME_MAX];
+        char prop_value[PROP_VALUE_MAX];
 
-    switch(msg.cmd) {
-    case PROP_MSG_SETPROP:
-        msg.name[PROP_NAME_MAX-1] = 0;
-        msg.value[PROP_VALUE_MAX-1] = 0;
-
-        if (!is_legal_property_name(msg.name)) {
-            LOG(ERROR) << "sys_prop: illegal property name \"" << msg.name << "\"";
-            close(s);
-            return;
+        if (!socket.RecvChars(prop_name, PROP_NAME_MAX, &timeout_ms) ||
+            !socket.RecvChars(prop_value, PROP_VALUE_MAX, &timeout_ms)) {
+          PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP): error while reading name/value from the socket";
+          return;
         }
 
-        getpeercon(s, &source_ctx);
+        prop_name[PROP_NAME_MAX-1] = 0;
+        prop_value[PROP_VALUE_MAX-1] = 0;
 
-        if(memcmp(msg.name,"ctl.",4) == 0) {
-            // Keep the old close-socket-early behavior when handling
-            // ctl.* properties.
-            close(s);
-            if (check_control_mac_perms(msg.value, source_ctx, &cr)) {
-                handle_control_message((char*) msg.name + 4, (char*) msg.value);
-            } else {
-                LOG(ERROR) << "sys_prop: Unable to " << (msg.name + 4)
-                           << " service ctl [" << msg.value << "]"
-                           << " uid:" << cr.uid
-                           << " gid:" << cr.gid
-                           << " pid:" << cr.pid;
-            }
-        } else {
-            if (check_mac_perms(msg.name, source_ctx, &cr)) {
-                property_set((char*) msg.name, (char*) msg.value);
-            } else {
-                LOG(ERROR) << "sys_prop: permission denied uid:" << cr.uid << " name:" << msg.name;
-            }
-
-            // Note: bionic's property client code assumes that the
-            // property server will not close the socket until *AFTER*
-            // the property is written to memory.
-            close(s);
-        }
-        freecon(source_ctx);
+        handle_property_set(socket, prop_value, prop_value, true);
         break;
+      }
 
+    case PROP_MSG_SETPROP2: {
+        std::string name;
+        std::string value;
+        if (!socket.RecvString(&name, &timeout_ms) ||
+            !socket.RecvString(&value, &timeout_ms)) {
+          PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP2): error while reading name/value from the socket";
+          socket.SendUint32(PROP_ERROR_READ_DATA);
+          return;
+        }
+
+        handle_property_set(socket, name, value, false);
+        break;
+      }
     default:
-        close(s);
+        socket.SendUint32(PROP_ERROR_INVALID_CMD);
         break;
     }
 }
@@ -510,6 +647,8 @@
 }
 
 void start_property_service() {
+    property_set("ro.property_service.version", "2");
+
     property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
                                     0666, 0, 0, NULL);
     if (property_set_fd == -1) {
diff --git a/init/property_service.h b/init/property_service.h
index e3a2acb..5d59473 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -27,14 +27,14 @@
     const char* name;
 };
 
-extern void property_init(void);
-extern void property_load_boot_defaults(void);
-extern void load_persist_props(void);
-extern void load_system_props(void);
-extern void start_property_service(void);
+void property_init(void);
+void property_load_boot_defaults(void);
+void load_persist_props(void);
+void load_system_props(void);
+void start_property_service(void);
 std::string property_get(const char* name);
-extern int property_set(const char *name, const char *value);
-extern bool is_legal_property_name(const std::string &name);
+uint32_t property_set(const std::string& name, const std::string& value);
+bool is_legal_property_name(const std::string& name);
 
 
 #endif  /* _INIT_PROPERTY_H */
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index f6c0f0e..b96e3ae 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -30,23 +30,6 @@
     "str_parms.c",
 ]
 
-cc_library_headers {
-    name: "libcutils_vndk_headers",
-    host_supported: true,
-    export_include_dirs: ["include_vndk"],
-}
-
-cc_library_headers {
-    name: "libcutils_headers",
-    host_supported: true,
-    export_include_dirs: ["include"],
-    target: {
-       windows: {
-          enabled: true,
-       },
-    },
-}
-
 cc_library {
     name: "libcutils",
     host_supported: true,
@@ -68,7 +51,6 @@
         "threads.c",
     ],
 
-
     target: {
         host: {
             srcs: ["dlmalloc_stubs.c"],
@@ -135,9 +117,6 @@
     },
 
     shared_libs: ["liblog"],
-    header_libs: ["libcutils_headers"],
-    export_header_lib_headers: ["libcutils_headers"],
-
     product_variables: {
         cpusets: {
             cflags: ["-DUSE_CPUSETS"],
diff --git a/libcutils/include_vndk/cutils/android_get_control_file.h b/libcutils/include_vndk/cutils/android_get_control_file.h
deleted file mode 120000
index 70d6a3b..0000000
--- a/libcutils/include_vndk/cutils/android_get_control_file.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/android_get_control_file.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/android_reboot.h b/libcutils/include_vndk/cutils/android_reboot.h
deleted file mode 120000
index 9e1bf4c..0000000
--- a/libcutils/include_vndk/cutils/android_reboot.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/android_reboot.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/ashmem.h b/libcutils/include_vndk/cutils/ashmem.h
deleted file mode 120000
index 5c07beb..0000000
--- a/libcutils/include_vndk/cutils/ashmem.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/ashmem.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/atomic.h b/libcutils/include_vndk/cutils/atomic.h
deleted file mode 120000
index f4f14fe..0000000
--- a/libcutils/include_vndk/cutils/atomic.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/atomic.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/bitops.h b/libcutils/include_vndk/cutils/bitops.h
deleted file mode 120000
index edbd60c..0000000
--- a/libcutils/include_vndk/cutils/bitops.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/bitops.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/compiler.h b/libcutils/include_vndk/cutils/compiler.h
deleted file mode 120000
index 08ebc10..0000000
--- a/libcutils/include_vndk/cutils/compiler.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/compiler.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/config_utils.h b/libcutils/include_vndk/cutils/config_utils.h
deleted file mode 120000
index e011738..0000000
--- a/libcutils/include_vndk/cutils/config_utils.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/config_utils.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/fs.h b/libcutils/include_vndk/cutils/fs.h
deleted file mode 120000
index 576bfa3..0000000
--- a/libcutils/include_vndk/cutils/fs.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/fs.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/hashmap.h b/libcutils/include_vndk/cutils/hashmap.h
deleted file mode 120000
index 6b18406..0000000
--- a/libcutils/include_vndk/cutils/hashmap.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/hashmap.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/iosched_policy.h b/libcutils/include_vndk/cutils/iosched_policy.h
deleted file mode 120000
index 26cf333..0000000
--- a/libcutils/include_vndk/cutils/iosched_policy.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/iosched_policy.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/jstring.h b/libcutils/include_vndk/cutils/jstring.h
deleted file mode 120000
index f3fd546..0000000
--- a/libcutils/include_vndk/cutils/jstring.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/jstring.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/klog.h b/libcutils/include_vndk/cutils/klog.h
deleted file mode 120000
index 8ca85ff..0000000
--- a/libcutils/include_vndk/cutils/klog.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/klog.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/list.h b/libcutils/include_vndk/cutils/list.h
deleted file mode 120000
index 9fa4c90..0000000
--- a/libcutils/include_vndk/cutils/list.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/list.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/log.h b/libcutils/include_vndk/cutils/log.h
deleted file mode 100644
index ae74024..0000000
--- a/libcutils/include_vndk/cutils/log.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*Special log.h file for VNDK linking modules*/
-/*
- * Copyright (C) 2005-2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
-#ifndef _LIBS_CUTIL_LOG_H
-#define _LIBS_CUTIL_LOG_H
-#warning "Deprecated: don't include cutils/log.h, use either android/log.h or log/log.h"
-#include <log/log.h>
-#endif /* _LIBS_CUTIL_LOG_H */
diff --git a/libcutils/include_vndk/cutils/memory.h b/libcutils/include_vndk/cutils/memory.h
deleted file mode 120000
index e0e7abc..0000000
--- a/libcutils/include_vndk/cutils/memory.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/memory.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/misc.h b/libcutils/include_vndk/cutils/misc.h
deleted file mode 120000
index db09eb5..0000000
--- a/libcutils/include_vndk/cutils/misc.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/misc.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/multiuser.h b/libcutils/include_vndk/cutils/multiuser.h
deleted file mode 120000
index 524111f..0000000
--- a/libcutils/include_vndk/cutils/multiuser.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/multiuser.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/native_handle.h b/libcutils/include_vndk/cutils/native_handle.h
deleted file mode 120000
index e324d4e..0000000
--- a/libcutils/include_vndk/cutils/native_handle.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/native_handle.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/open_memstream.h b/libcutils/include_vndk/cutils/open_memstream.h
deleted file mode 120000
index c894084..0000000
--- a/libcutils/include_vndk/cutils/open_memstream.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/open_memstream.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/partition_utils.h b/libcutils/include_vndk/cutils/partition_utils.h
deleted file mode 120000
index d9734c8..0000000
--- a/libcutils/include_vndk/cutils/partition_utils.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/partition_utils.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/properties.h b/libcutils/include_vndk/cutils/properties.h
deleted file mode 120000
index d56118e..0000000
--- a/libcutils/include_vndk/cutils/properties.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/properties.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/qtaguid.h b/libcutils/include_vndk/cutils/qtaguid.h
deleted file mode 120000
index bc02441..0000000
--- a/libcutils/include_vndk/cutils/qtaguid.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/qtaguid.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/record_stream.h b/libcutils/include_vndk/cutils/record_stream.h
deleted file mode 120000
index 8de6494..0000000
--- a/libcutils/include_vndk/cutils/record_stream.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/record_stream.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/sched_policy.h b/libcutils/include_vndk/cutils/sched_policy.h
deleted file mode 120000
index ddebdd0..0000000
--- a/libcutils/include_vndk/cutils/sched_policy.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/sched_policy.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/sockets.h b/libcutils/include_vndk/cutils/sockets.h
deleted file mode 120000
index 585250c..0000000
--- a/libcutils/include_vndk/cutils/sockets.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/sockets.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/str_parms.h b/libcutils/include_vndk/cutils/str_parms.h
deleted file mode 120000
index 9c79a8f..0000000
--- a/libcutils/include_vndk/cutils/str_parms.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/str_parms.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/threads.h b/libcutils/include_vndk/cutils/threads.h
deleted file mode 120000
index 99330ff..0000000
--- a/libcutils/include_vndk/cutils/threads.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/threads.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/trace.h b/libcutils/include_vndk/cutils/trace.h
deleted file mode 120000
index b12e140..0000000
--- a/libcutils/include_vndk/cutils/trace.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/trace.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/cutils/uevent.h b/libcutils/include_vndk/cutils/uevent.h
deleted file mode 120000
index 451283a..0000000
--- a/libcutils/include_vndk/cutils/uevent.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/uevent.h
\ No newline at end of file
diff --git a/libcutils/klog.cpp b/libcutils/klog.cpp
index 15adf6b..d301276 100644
--- a/libcutils/klog.cpp
+++ b/libcutils/klog.cpp
@@ -29,10 +29,6 @@
 
 static int klog_level = KLOG_INFO_LEVEL;
 
-int klog_get_level(void) {
-    return klog_level;
-}
-
 void klog_set_level(int level) {
     klog_level = level;
 }
diff --git a/liblog/Android.bp b/liblog/Android.bp
index dce316d..40cdcee 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -79,8 +79,6 @@
         },
     },
 
-    export_include_dirs: ["include"],
-
     cflags: [
         "-Werror",
         "-fvisibility=hidden",
@@ -113,11 +111,6 @@
     license: "NOTICE",
 }
 
-cc_library_headers {
-    name: "liblog_vndk_headers",
-    export_include_dirs: ["include_vndk"],
-}
-
 ndk_library {
     name: "liblog.ndk",
     symbol_file: "liblog.map.txt",
diff --git a/liblog/include/log/logd.h b/liblog/include/log/logd.h
deleted file mode 100644
index 77400ca..0000000
--- a/liblog/include/log/logd.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifndef _LIBS_LOG_LOGD_H
-#define _LIBS_LOG_LOGD_H
-#include <log/log.h>
-#warning "Deprecated: do not include log/logd.h, use log/log.h instead"
-#endif /*_LIBS_LOG_LOGD_H*/
diff --git a/liblog/include/log/logger.h b/liblog/include/log/logger.h
deleted file mode 100644
index 1bf2d17..0000000
--- a/liblog/include/log/logger.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifndef _LIBS_LOG_LOGGER_H
-#define _LIBS_LOG_LOGGER_H
-#include <log/log.h>
-#warning "Deprecated: do not include log/logger.h, use log/log.h instead"
-#endif /*_LIBS_LOG_LOGGER_H*/
diff --git a/liblog/include_vndk/android b/liblog/include_vndk/android
deleted file mode 120000
index 69fbc09..0000000
--- a/liblog/include_vndk/android
+++ /dev/null
@@ -1 +0,0 @@
-../../include/android/
\ No newline at end of file
diff --git a/liblog/include_vndk/log/log.h b/liblog/include_vndk/log/log.h
deleted file mode 100644
index f3eb3fe..0000000
--- a/liblog/include_vndk/log/log.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*Special log.h file for VNDK linking modules*/
-
-#ifndef _LIBS_LOG_LOG_H
-#define _LIBS_LOG_LOG_H
-
-#include <android/log.h>
-
-/*The following files will be included once they are available*/
-/*#include <log/log_id.h>*/
-/*#include <log/log_radio.h>*/
-
-/*
- * LOG_TAG is the local tag used for the following simplified
- * logging macros.  You can change this preprocessor definition
- * before using the other macros to change the tag.
- */
-
-#ifndef LOG_TAG
-#define LOG_TAG NULL
-#endif
-
-#endif /*_LIBS_LOG_LOG_H*/