Merge "Revert "Make libutils test compile on the host""
diff --git a/adb/adb.cpp b/adb/adb.cpp
index ece143c..577e9b9 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -1129,6 +1129,18 @@
         return 0;
     }
 
+#if ADB_HOST
+    if (!strcmp(service, "host-features")) {
+        FeatureSet features = supported_features();
+        // Abuse features to report libusb status.
+        if (should_use_libusb()) {
+            features.insert(kFeatureLibusb);
+        }
+        SendOkay(reply_fd, FeatureSetToString(features));
+        return 0;
+    }
+#endif
+
     // remove TCP transport
     if (!strncmp(service, "disconnect:", 11)) {
         const std::string address(service + 11);
diff --git a/adb/adb.h b/adb/adb.h
index a30e297..aea5fb8 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -54,7 +54,7 @@
 std::string adb_version();
 
 // Increment this when we want to force users to start a new adb server.
-#define ADB_SERVER_VERSION 38
+#define ADB_SERVER_VERSION 39
 
 class atransport;
 
diff --git a/adb/client/usb_dispatch.cpp b/adb/client/usb_dispatch.cpp
index f02dccf..bfc8e16 100644
--- a/adb/client/usb_dispatch.cpp
+++ b/adb/client/usb_dispatch.cpp
@@ -17,11 +17,6 @@
 #include <android-base/logging.h>
 #include "usb.h"
 
-static bool should_use_libusb() {
-    static bool enable = getenv("ADB_LIBUSB") && strcmp(getenv("ADB_LIBUSB"), "1") == 0;
-    return enable;
-}
-
 void usb_init() {
     if (should_use_libusb()) {
         LOG(DEBUG) << "using libusb backend";
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 3b2df2e..5a2206f 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -1929,8 +1929,7 @@
     else if (!strcmp(argv[0], "--version") || !strcmp(argv[0], "version")) {
         fprintf(stdout, "%s", adb_version().c_str());
         return 0;
-    }
-    else if (!strcmp(argv[0], "features")) {
+    } else if (!strcmp(argv[0], "features")) {
         // Only list the features common to both the adb client and the device.
         FeatureSet features;
         std::string error;
@@ -1945,6 +1944,8 @@
             }
         }
         return 0;
+    } else if (!strcmp(argv[0], "host-features")) {
+        return adb_query_command("host:host-features");
     } else if (!strcmp(argv[0], "reconnect")) {
         if (argc == 1) {
             return adb_query_command("host:reconnect");
diff --git a/adb/set_verity_enable_state_service.cpp b/adb/set_verity_enable_state_service.cpp
index f9e028b..76b156d 100644
--- a/adb/set_verity_enable_state_service.cpp
+++ b/adb/set_verity_enable_state_service.cpp
@@ -108,11 +108,10 @@
         return;
     }
 
-    std::string fstab_filename = "/fstab." + android::base::GetProperty("ro.hardware", "");
-
-    fstab = fs_mgr_read_fstab(fstab_filename.c_str());
+    // read all fstab entries at once from all sources
+    fstab = fs_mgr_read_fstab_default();
     if (!fstab) {
-        WriteFdFmt(fd, "Failed to open %s\nMaybe run adb root?\n", fstab_filename.c_str());
+        WriteFdFmt(fd, "Failed to read fstab\nMaybe run adb root?\n");
         return;
     }
 
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 60f3b5c..c951f5b 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -51,6 +51,7 @@
 const char* const kFeatureShell2 = "shell_v2";
 const char* const kFeatureCmd = "cmd";
 const char* const kFeatureStat2 = "stat_v2";
+const char* const kFeatureLibusb = "libusb";
 
 static std::string dump_packet(const char* name, const char* func, apacket* p) {
     unsigned command = p->msg.command;
diff --git a/adb/transport.h b/adb/transport.h
index 3306388..490e513 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -47,6 +47,8 @@
 // The 'cmd' command is available
 extern const char* const kFeatureCmd;
 extern const char* const kFeatureStat2;
+// The server is running with libusb enabled.
+extern const char* const kFeatureLibusb;
 
 class atransport {
 public:
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index 3d6cc99..e16cf12 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -97,3 +97,12 @@
 {
     return (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && usb_protocol == ADB_PROTOCOL);
 }
+
+bool should_use_libusb() {
+#if defined(_WIN32) || !ADB_HOST
+    return false;
+#else
+    static bool enable = getenv("ADB_LIBUSB") && strcmp(getenv("ADB_LIBUSB"), "1") == 0;
+    return enable;
+#endif
+}
diff --git a/adb/usb.h b/adb/usb.h
index 879bacc..ba70de4 100644
--- a/adb/usb.h
+++ b/adb/usb.h
@@ -55,3 +55,5 @@
 
 // USB device detection.
 int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol);
+
+bool should_use_libusb();
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index 50677a3..e78edbb 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -17,6 +17,37 @@
 #ifndef ANDROID_BASE_LOGGING_H
 #define ANDROID_BASE_LOGGING_H
 
+//
+// Google-style C++ logging.
+//
+
+// This header provides a C++ stream interface to logging.
+//
+// To log:
+//
+//   LOG(INFO) << "Some text; " << some_value;
+//
+// Replace `INFO` with any severity from `enum LogSeverity`.
+//
+// To log the result of a failed function and include the string
+// representation of `errno` at the end:
+//
+//   PLOG(ERROR) << "Write failed";
+//
+// The output will be something like `Write failed: I/O error`.
+// Remember this as 'P' as in perror(3).
+//
+// To output your own types, simply implement operator<< as normal.
+//
+// By default, output goes to logcat on Android and stderr on the host.
+// A process can use `SetLogger` to decide where all logging goes.
+// Implementations are provided for logcat, stderr, and dmesg.
+
+// This header also provides assertions:
+//
+//   CHECK(must_be_true);
+//   CHECK_EQ(a, b) << z_is_interesting_too;
+
 // NOTE: For Windows, you must include logging.h after windows.h to allow the
 // following code to suppress the evil ERROR macro:
 #ifdef _WIN32
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 6939428..f1a7ad6 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -25,7 +25,8 @@
     fs_mgr_slotselect.cpp \
     fs_mgr_verity.cpp \
     fs_mgr_avb.cpp \
-    fs_mgr_avb_ops.cpp
+    fs_mgr_avb_ops.cpp \
+    fs_mgr_boot_config.cpp
 LOCAL_C_INCLUDES := \
     $(LOCAL_PATH)/include \
     system/vold \
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 1768078..25c41b9 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -48,7 +48,6 @@
 
 #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"
 #define KEY_IN_FOOTER  "footer"
@@ -661,6 +660,8 @@
     }
 }
 
+// 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) {
     int tries = 25;
     while (tries--) {
@@ -880,6 +881,24 @@
     }
 }
 
+/* wrapper to __mount() and expects a fully prepared fstab_rec,
+ * unlike fs_mgr_do_mount which does more things with avb / verity
+ * etc.
+ */
+int fs_mgr_do_mount_one(struct fstab_rec *rec)
+{
+    if (!rec) {
+        return FS_MGR_DOMNT_FAILED;
+    }
+
+    int ret = __mount(rec->blk_device, rec->mount_point, rec);
+    if (ret) {
+      ret = (errno == EBUSY) ? FS_MGR_DOMNT_BUSY : FS_MGR_DOMNT_FAILED;
+    }
+
+    return ret;
+}
+
 /* If tmp_mount_point is non-null, mount the filesystem there.  This is for the
  * tmp mount we do to check the user password
  * If multiple fstab entries are to be mounted on "n_name", it will try to mount each one
@@ -1171,22 +1190,3 @@
 
     return 0;
 }
-
-int fs_mgr_early_setup_verity(struct fstab_rec *fstab_rec)
-{
-    if ((fstab_rec->fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
-        int rc = fs_mgr_setup_verity(fstab_rec, false);
-        if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
-            LINFO << "Verity disabled";
-            return FS_MGR_EARLY_SETUP_VERITY_NO_VERITY;
-        } else if (rc == FS_MGR_SETUP_VERITY_SUCCESS) {
-            return FS_MGR_EARLY_SETUP_VERITY_SUCCESS;
-        } else {
-            return FS_MGR_EARLY_SETUP_VERITY_FAIL;
-        }
-    } else if (device_is_secure()) {
-        LERROR << "Verity must be enabled for early mounted partitions on secured devices";
-        return FS_MGR_EARLY_SETUP_VERITY_FAIL;
-    }
-    return FS_MGR_EARLY_SETUP_VERITY_NO_VERITY;
-}
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index 68efb00..2cb7e34 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -441,18 +441,23 @@
 
 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}.
+    // 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 = android::base::GetProperty("ro.boot.vbmeta.hash_alg", "");
-
-    if (hash_alg == "sha256" || hash_alg == "sha512") {
-        return true;
+    std::string hash_alg;
+    if (fs_mgr_get_boot_config("vbmeta.hash_alg", &hash_alg) == 0) {
+        if (hash_alg == "sha256" || hash_alg == "sha512") {
+            return true;
+        }
     }
 
     return false;
@@ -482,10 +487,11 @@
     // 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();
+    const char *requested_partitions[] = {nullptr};
+    std::string ab_suffix;
+    fs_mgr_get_boot_config("slot_suffix", &ab_suffix);
     AvbSlotVerifyResult verify_result =
-        avb_slot_verify(fs_mgr_avb_ops, requested_partitions, ab_suffix,
+        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);
 
     // Only allow two verify results:
diff --git a/fs_mgr/fs_mgr_boot_config.cpp b/fs_mgr/fs_mgr_boot_config.cpp
new file mode 100644
index 0000000..9decb27
--- /dev/null
+++ b/fs_mgr/fs_mgr_boot_config.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/properties.h>
+
+#include "fs_mgr_priv.h"
+
+// Tries to get the boot config value in properties, kernel cmdline and
+// device tree (in that order).  returns 'true' if successfully found, 'false'
+// otherwise
+bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val) {
+    FS_MGR_CHECK(out_val != nullptr);
+
+    // first check if we have "ro.boot" property already
+    *out_val = android::base::GetProperty("ro.boot." + key, "");
+    if (!out_val->empty()) {
+        return true;
+    }
+
+    // fallback to kernel cmdline, properties may not be ready yet
+    std::string cmdline;
+    std::string cmdline_key("androidboot." + key);
+    if (android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
+        for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) {
+            std::vector<std::string> pieces = android::base::Split(entry, "=");
+            if (pieces.size() == 2) {
+                if (pieces[0] == cmdline_key) {
+                    *out_val = pieces[1];
+                    return true;
+                }
+            }
+        }
+    }
+
+    // lastly, check the device tree
+    std::string file_name = kAndroidDtDir + "/compatible";
+    std::string dt_value;
+    if (android::base::ReadFileToString(file_name, &dt_value)) {
+        if (dt_value != "android,firmware") {
+            LERROR << "Error finding compatible android DT node";
+            return false;
+        }
+
+        file_name = kAndroidDtDir + "/" + key;
+        // DT entries terminate with '\0' but so do the properties
+        if (android::base::ReadFileToString(file_name, out_val)) {
+            return true;
+        }
+
+        LERROR << "Error finding '" << key << "' in device tree";
+    }
+
+    return false;
+}
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 48ddf29..f989787 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <ctype.h>
+#include <dirent.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -22,6 +23,10 @@
 #include <sys/mount.h>
 #include <unistd.h>
 
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
 #include "fs_mgr_priv.h"
 
 struct fs_mgr_flag_values {
@@ -290,6 +295,110 @@
     return f;
 }
 
+static bool is_dt_compatible() {
+    std::string file_name = kAndroidDtDir + "/compatible";
+    std::string dt_value;
+    if (android::base::ReadFileToString(file_name, &dt_value)) {
+        // trim the trailing '\0' out, otherwise the comparison
+        // will produce false-negatives.
+        dt_value.resize(dt_value.size() - 1);
+        if (dt_value == "android,firmware") {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+static bool is_dt_fstab_compatible() {
+    std::string dt_value;
+    std::string file_name = kAndroidDtDir + "/fstab/compatible";
+
+    if (android::base::ReadFileToString(file_name, &dt_value)) {
+        // trim the trailing '\0' out, otherwise the comparison
+        // will produce false-negatives.
+        dt_value.resize(dt_value.size() - 1);
+        if (dt_value == "android,fstab") {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+static std::string read_fstab_from_dt() {
+    std::string fstab;
+    if (!is_dt_compatible() || !is_dt_fstab_compatible()) {
+        return fstab;
+    }
+
+    std::string fstabdir_name = kAndroidDtDir + "/fstab";
+    std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir);
+    if (!fstabdir) return fstab;
+
+    dirent* dp;
+    while ((dp = readdir(fstabdir.get())) != NULL) {
+        // skip over name and compatible
+        if (dp->d_type != DT_DIR) {
+            continue;
+        }
+
+        // skip if its not 'vendor', 'odm' or 'system'
+        if (strcmp(dp->d_name, "odm") && strcmp(dp->d_name, "system") &&
+            strcmp(dp->d_name, "vendor")) {
+            continue;
+        }
+
+        // create <dev> <mnt_point>  <type>  <mnt_flags>  <fsmgr_flags>\n
+        std::vector<std::string> fstab_entry;
+        std::string file_name;
+        std::string value;
+        file_name = android::base::StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
+        if (!android::base::ReadFileToString(file_name, &value)) {
+            LERROR << "dt_fstab: Failed to find device for partition " << dp->d_name;
+            fstab.clear();
+            break;
+        }
+        // trim the terminating '\0' out
+        value.resize(value.size() - 1);
+        fstab_entry.push_back(value);
+        fstab_entry.push_back(android::base::StringPrintf("/%s", dp->d_name));
+
+        file_name = android::base::StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name);
+        if (!android::base::ReadFileToString(file_name, &value)) {
+            LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
+            fstab.clear();
+            break;
+        }
+        value.resize(value.size() - 1);
+        fstab_entry.push_back(value);
+
+        file_name = android::base::StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
+        if (!android::base::ReadFileToString(file_name, &value)) {
+            LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
+            fstab.clear();
+            break;
+        }
+        value.resize(value.size() - 1);
+        fstab_entry.push_back(value);
+
+        file_name = android::base::StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
+        if (!android::base::ReadFileToString(file_name, &value)) {
+            LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
+            fstab.clear();
+            break;
+        }
+        value.resize(value.size() - 1);
+        fstab_entry.push_back(value);
+
+        fstab += android::base::Join(fstab_entry, " ");
+        fstab += '\n';
+    }
+
+    return fstab;
+}
+
+
 struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file)
 {
     int cnt, entries;
@@ -444,6 +553,84 @@
     return fstab;
 }
 
+/* Returns fstab entries parsed from the device tree if they
+ * exist
+ */
+struct fstab *fs_mgr_read_fstab_dt()
+{
+    std::string fstab_buf = read_fstab_from_dt();
+    if (fstab_buf.empty()) {
+        return NULL;
+    }
+
+    std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
+        fmemopen(static_cast<void*>(const_cast<char*>(fstab_buf.c_str())),
+                 fstab_buf.length(), "r"), fclose);
+    if (!fstab_file) {
+        return NULL;
+    }
+
+    struct fstab *fstab = fs_mgr_read_fstab_file(fstab_file.get());
+    if (!fstab) {
+        LERROR << "failed to load fstab from kernel:" << std::endl << fstab_buf;
+    }
+
+    return fstab;
+}
+
+/* combines fstab entries passed in from device tree with
+ * the ones found in /fstab.<hardware>
+ */
+struct fstab *fs_mgr_read_fstab_default()
+{
+    struct fstab *fstab = fs_mgr_read_fstab_dt();
+    std::string hw;
+    if (!fs_mgr_get_boot_config("hardware", &hw)) {
+        // if we fail to find this, return whatever was found in device tree
+        LWARNING << "failed to find device hardware name";
+        return fstab;
+    }
+
+    std::string default_fstab = FSTAB_PREFIX + hw;
+    struct fstab *f = fs_mgr_read_fstab(default_fstab.c_str());
+    if (!f) {
+        // return what we have
+        LWARNING << "failed to read fstab entries from '" << default_fstab << "'";
+        return fstab;
+    }
+
+    // return the fstab read from file if device tree doesn't
+    // have one, other wise merge the two
+    if (!fstab) {
+        fstab = f;
+    } else {
+        int total_entries = fstab->num_entries + f->num_entries;
+        fstab->recs = static_cast<struct fstab_rec *>(realloc(
+                        fstab->recs, total_entries * (sizeof(struct fstab_rec))));
+        if (!fstab->recs) {
+            LERROR << "failed to allocate fstab recs";
+            fstab->num_entries = 0;
+            fs_mgr_free_fstab(fstab);
+            return NULL;
+        }
+
+        for (int i = fstab->num_entries, j = 0; i < total_entries; i++, j++) {
+            // copy everything and *not* strdup
+            fstab->recs[i] = f->recs[j];
+        }
+
+        // free up fstab entries read from file, but don't cleanup
+        // the strings within f->recs[X] to make sure they are accessible
+        // through fstab->recs[X].
+        free(f->fstab_filename);
+        free(f);
+
+        fstab->num_entries = total_entries;
+    }
+
+    return fstab;
+}
+
 void fs_mgr_free_fstab(struct fstab *fstab)
 {
     int i;
@@ -557,6 +744,11 @@
     return fstab->fs_mgr_flags & MF_VERIFY;
 }
 
+int fs_mgr_is_verifyatboot(const struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_VERIFYATBOOT;
+}
+
 int fs_mgr_is_encryptable(const struct fstab_rec *fstab)
 {
     return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE);
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 79c27c4..95295d8 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -19,6 +19,7 @@
 
 #include <android-base/logging.h>
 #include <fs_mgr.h>
+#include "fs_mgr_priv_boot_config.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
@@ -40,6 +41,8 @@
 #define PWARNING PLOG(WARNING) << FS_MGR_TAG
 #define PERROR   PLOG(ERROR) << FS_MGR_TAG
 
+const std::string FSTAB_PREFIX("/fstab.");
+
 __BEGIN_DECLS
 
 #define CRYPTO_TMPFS_OPTIONS "size=256m,mode=0771,uid=1000,gid=1000"
diff --git a/fs_mgr/fs_mgr_priv_verity.h b/fs_mgr/fs_mgr_priv_boot_config.h
similarity index 63%
rename from fs_mgr/fs_mgr_priv_verity.h
rename to fs_mgr/fs_mgr_priv_boot_config.h
index 1a6d215..8773d33 100644
--- a/fs_mgr/fs_mgr_priv_verity.h
+++ b/fs_mgr/fs_mgr_priv_boot_config.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 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.
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
+#ifndef __CORE_FS_MGR_PRIV_BOOTCONFIG_H
+#define __CORE_FS_MGR_PRIV_BOOTCONFIG_H
+
 #include <sys/cdefs.h>
+#include <string>
 
-#define FS_MGR_SETUP_VERITY_DISABLED (-2)
-#define FS_MGR_SETUP_VERITY_FAIL (-1)
-#define FS_MGR_SETUP_VERITY_SUCCESS 0
+const std::string kAndroidDtDir("/proc/device-tree/firmware/android");
 
-__BEGIN_DECLS
+bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val);
 
-int fs_mgr_setup_verity(struct fstab_rec *fstab, bool verify_dev);
-
-__END_DECLS
+#endif /* __CORE_FS_MGR_PRIV_BOOTCONFIG_H */
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp
index b30417f..f3bba7b 100644
--- a/fs_mgr/fs_mgr_slotselect.cpp
+++ b/fs_mgr/fs_mgr_slotselect.cpp
@@ -14,118 +14,31 @@
  * limitations under the License.
  */
 
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <ctype.h>
-#include <errno.h>
 #include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <cutils/properties.h>
 
 #include "fs_mgr.h"
 #include "fs_mgr_priv.h"
 
-// finds slot_suffix in androidboot.slot_suffix kernel command line argument
-// or in the device tree node at /firmware/android/slot_suffix property
-static int get_active_slot_suffix_from_kernel(char *out_suffix,
-                                              size_t suffix_len)
-{
-    std::string cmdline;
-    if (android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
-        for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) {
-            std::vector<std::string> pieces = android::base::Split(entry, "=");
-            if (pieces.size() == 2) {
-                if (pieces[0] == "androidboot.slot_suffix") {
-                    strncpy(out_suffix, pieces[1].c_str(), suffix_len);
-                    return 0;
-                }
-            }
-        }
-    }
-
-    // if we can't find slot_suffix in cmdline, check the DT
-    static constexpr char android_dt_dir[] = "/proc/device-tree/firmware/android";
-    std::string file_name = android::base::StringPrintf("%s/compatible", android_dt_dir);
-    std::string dt_value;
-    if (android::base::ReadFileToString(file_name, &dt_value)) {
-        if (!dt_value.compare("android,firmware")) {
-            LERROR << "Error finding compatible android DT node";
-            return -1;
-        }
-
-        file_name = android::base::StringPrintf("%s/%s", android_dt_dir, "slot_suffix");
-        if (!android::base::ReadFileToString(file_name, &dt_value)) {
-            LERROR << "Error finding slot_suffix in device tree";
-            return -1;
-        }
-
-        // DT entries have a terminating '\0', so 'suffix_len' is safe.
-        strncpy(out_suffix, dt_value.c_str(), suffix_len);
-        return 0;
-    }
-
-    // slot_suffix missing in kernel cmdline or device tree
-    return -1;
-}
-
-// Gets slot_suffix from either the kernel cmdline / device tree.  Sets
-// |out_suffix| on success and returns 0. Returns -1 if slot_suffix could not
-// be determined.
-static int get_active_slot_suffix(char *out_suffix, size_t suffix_len)
-{
-    char propbuf[PROPERTY_VALUE_MAX];
-
-    // Get the suffix from the kernel commandline (note that we don't
-    // allow the empty suffix). On bootloaders natively supporting A/B
-    // we'll hit this path every time so don't bother logging it.
-    property_get("ro.boot.slot_suffix", propbuf, "");
-    if (propbuf[0] != '\0') {
-        strncpy(out_suffix, propbuf, suffix_len);
-        return 0;
-    }
-
-    // if the property is not set, we are probably being invoked early during
-    // boot.  Try to find the slotsuffix ourselves in the kernel command line
-    // or the device tree
-    if (get_active_slot_suffix_from_kernel(out_suffix, suffix_len) == 0) {
-        LINFO << "Using slot suffix '" << out_suffix << "' from kernel";
-        return 0;
-    }
-
-    LERROR << "Error determining slot_suffix";
-
-    return -1;
-}
-
 // Updates |fstab| for slot_suffix. Returns 0 on success, -1 on error.
 int fs_mgr_update_for_slotselect(struct fstab *fstab)
 {
     int n;
-    char suffix[PROPERTY_VALUE_MAX];
     int got_suffix = 0;
+    std::string suffix;
 
     for (n = 0; n < fstab->num_entries; n++) {
         if (fstab->recs[n].fs_mgr_flags & MF_SLOTSELECT) {
             char *tmp;
 
             if (!got_suffix) {
-                memset(suffix, '\0', sizeof(suffix));
-                if (get_active_slot_suffix(suffix, sizeof(suffix) - 1) != 0) {
+                if (!fs_mgr_get_boot_config("slot_suffix", &suffix)) {
                   return -1;
                 }
                 got_suffix = 1;
             }
 
             if (asprintf(&tmp, "%s%s", fstab->recs[n].blk_device,
-                         suffix) > 0) {
+                         suffix.c_str()) > 0) {
                 free(fstab->recs[n].blk_device);
                 fstab->recs[n].blk_device = tmp;
             } else {
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 1ec4540..5b81a54 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -45,9 +45,6 @@
 #include "fs_mgr.h"
 #include "fs_mgr_priv.h"
 #include "fs_mgr_priv_dm_ioctl.h"
-#include "fs_mgr_priv_verity.h"
-
-#define FSTAB_PREFIX "/fstab."
 
 #define VERITY_TABLE_RSA_KEY "/verity_key"
 #define VERITY_TABLE_HASH_IDX 8
@@ -658,7 +655,6 @@
 
 static int load_verity_state(struct fstab_rec *fstab, int *mode)
 {
-    char propbuf[PROPERTY_VALUE_MAX];
     int match = 0;
     off64_t offset = 0;
 
@@ -666,10 +662,9 @@
     *mode = VERITY_MODE_EIO;
 
     /* use the kernel parameter if set */
-    property_get("ro.boot.veritymode", propbuf, "");
-
-    if (*propbuf != '\0') {
-        if (!strcmp(propbuf, "enforcing")) {
+    std::string veritymode;
+    if (fs_mgr_get_boot_config("veritymode", &veritymode)) {
+        if (veritymode.compare("enforcing")) {
             *mode = VERITY_MODE_DEFAULT;
         }
         return 0;
@@ -697,8 +692,6 @@
 
 int fs_mgr_load_verity_state(int *mode)
 {
-    char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
-    char propbuf[PROPERTY_VALUE_MAX];
     int rc = -1;
     int i;
     int current;
@@ -708,13 +701,9 @@
      * logging mode, in which case return that */
     *mode = VERITY_MODE_DEFAULT;
 
-    property_get("ro.hardware", propbuf, "");
-    snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
-
-    fstab = fs_mgr_read_fstab(fstab_filename);
-
+    fstab = fs_mgr_read_fstab_default();
     if (!fstab) {
-        LERROR << "Failed to read " << fstab_filename;
+        LERROR << "Failed to read default fstab";
         goto out;
     }
 
@@ -748,7 +737,6 @@
 {
     alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
     bool system_root = false;
-    char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
     std::string mount_point;
     char propbuf[PROPERTY_VALUE_MAX];
     const char *status;
@@ -768,22 +756,16 @@
     }
 
     fd = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));
-
     if (fd == -1) {
         PERROR << "Error opening device mapper";
         goto out;
     }
 
-    property_get("ro.hardware", propbuf, "");
-    snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
-
     property_get("ro.build.system_root_image", propbuf, "");
     system_root = !strcmp(propbuf, "true");
-
-    fstab = fs_mgr_read_fstab(fstab_filename);
-
+    fstab = fs_mgr_read_fstab_default();
     if (!fstab) {
-        LERROR << "Failed to read " << fstab_filename;
+        LERROR << "Failed to read default fstab";
         goto out;
     }
 
@@ -859,7 +841,10 @@
     *table = strdup(result.c_str());
 }
 
-int fs_mgr_setup_verity(struct fstab_rec *fstab, bool verify_dev)
+// prepares the verity enabled (MF_VERIFY / MF_VERIFYATBOOT) fstab record for
+// mount. The 'wait_for_verity_dev' parameter makes this function wait for the
+// verity device to get created before return
+int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev)
 {
     int retval = FS_MGR_SETUP_VERITY_FAIL;
     int fd = -1;
@@ -1026,7 +1011,7 @@
     }
 
     // make sure we've set everything up properly
-    if (verify_dev && fs_mgr_test_access(fstab->blk_device) < 0) {
+    if (wait_for_verity_dev && fs_mgr_test_access(fstab->blk_device) < 0) {
         goto out;
     }
 
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index a9deed9..52f27ab 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -85,6 +85,8 @@
 typedef void (*fs_mgr_verity_state_callback)(struct fstab_rec *fstab,
         const char *mount_point, int mode, int status);
 
+struct fstab *fs_mgr_read_fstab_default();
+struct fstab *fs_mgr_read_fstab_dt();
 struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file);
 struct fstab *fs_mgr_read_fstab(const char *fstab_path);
 void fs_mgr_free_fstab(struct fstab *fstab);
@@ -103,6 +105,7 @@
 
 int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
                     char *tmp_mount_point);
+int fs_mgr_do_mount_one(struct fstab_rec *rec);
 int fs_mgr_do_tmpfs_mount(char *n_name);
 int fs_mgr_unmount_all(struct fstab *fstab);
 int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc,
@@ -116,6 +119,7 @@
 int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab);
 int fs_mgr_is_nonremovable(const struct fstab_rec *fstab);
 int fs_mgr_is_verified(const struct fstab_rec *fstab);
+int fs_mgr_is_verifyatboot(const struct fstab_rec *fstab);
 int fs_mgr_is_encryptable(const struct fstab_rec *fstab);
 int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab);
 const char* fs_mgr_get_file_encryption_mode(const struct fstab_rec *fstab);
@@ -131,10 +135,10 @@
 
 int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer);
 
-#define FS_MGR_EARLY_SETUP_VERITY_NO_VERITY -2
-#define FS_MGR_EARLY_SETUP_VERITY_FAIL -1
-#define FS_MGR_EARLY_SETUP_VERITY_SUCCESS 0
-int fs_mgr_early_setup_verity(struct fstab_rec *fstab);
+#define FS_MGR_SETUP_VERITY_DISABLED (-2)
+#define FS_MGR_SETUP_VERITY_FAIL (-1)
+#define FS_MGR_SETUP_VERITY_SUCCESS 0
+int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev);
 
 #ifdef __cplusplus
 }
diff --git a/init/devices.cpp b/init/devices.cpp
index b3b808b..bd11f5f 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -251,7 +251,10 @@
      * some device nodes, so the uid has to be set with chown() and is still
      * racy. Fixing the gid race at least fixed the issue with system_server
      * opening dynamic input devices under the AID_INPUT gid. */
-    setegid(gid);
+    if (setegid(gid)) {
+        PLOG(ERROR) << "setegid(" << gid << ") for " << path << " device failed";
+        goto out;
+    }
     /* If the node already exists update its SELinux label to handle cases when
      * it was created with the wrong context during coldboot procedure. */
     if (mknod(path, mode, dev) && (errno == EEXIST) && secontext) {
@@ -273,7 +276,9 @@
 
 out:
     chown(path, uid, -1);
-    setegid(AID_ROOT);
+    if (setegid(AID_ROOT)) {
+        PLOG(FATAL) << "setegid(AID_ROOT) failed";
+    }
 
     if (secontext) {
         freecon(secontext);
@@ -999,15 +1004,20 @@
 }
 
 void device_init(const char* path, coldboot_callback fn) {
-    sehandle = selinux_android_file_context_handle();
-    selinux_status_open(true);
-
-    /* is 256K enough? udev uses 16MB! */
-    device_fd.reset(uevent_open_socket(256*1024, true));
-    if (device_fd == -1) {
-        return;
+    if (!sehandle) {
+        sehandle = selinux_android_file_context_handle();
     }
-    fcntl(device_fd, F_SETFL, O_NONBLOCK);
+    // open uevent socket and selinux status only if it hasn't been
+    // done before
+    if (device_fd == -1) {
+        /* is 256K enough? udev uses 16MB! */
+        device_fd.reset(uevent_open_socket(256 * 1024, true));
+        if (device_fd == -1) {
+            return;
+        }
+        fcntl(device_fd, F_SETFL, O_NONBLOCK);
+        selinux_status_open(true);
+    }
 
     if (access(COLDBOOT_DONE, F_OK) == 0) {
         LOG(VERBOSE) << "Skipping coldboot, already done!";
@@ -1040,6 +1050,7 @@
 void device_close() {
     destroy_platform_devices();
     device_fd.reset();
+    selinux_status_close();
 }
 
 int get_device_fd() {
diff --git a/init/init.cpp b/init/init.cpp
index 7f7eb2f..3cb1276 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -502,26 +502,30 @@
     std::string dt_value;
     std::string file_name = StringPrintf("%s/compatible", android_dt_dir);
 
-    android::base::ReadFileToString(file_name, &dt_value);
-    if (!dt_value.compare("android,firmware")) {
-        LOG(ERROR) << "firmware/android is not compatible with 'android,firmware'";
-        return false;
+    if (android::base::ReadFileToString(file_name, &dt_value)) {
+        // trim the trailing '\0' out, otherwise the comparison
+        // will produce false-negatives.
+        dt_value.resize(dt_value.size() - 1);
+        if (dt_value == "android,firmware") {
+            return true;
+        }
     }
 
-    return true;
+    return false;
 }
 
 static bool is_dt_fstab_compatible() {
     std::string dt_value;
     std::string file_name = StringPrintf("%s/%s/compatible", android_dt_dir, "fstab");
 
-    android::base::ReadFileToString(file_name, &dt_value);
-    if (!dt_value.compare("android,fstab")) {
-        LOG(ERROR) << "firmware/android/fstab is not compatible with 'android,fstab'";
-        return false;
+    if (android::base::ReadFileToString(file_name, &dt_value)) {
+        dt_value.resize(dt_value.size() - 1);
+        if (dt_value == "android,fstab") {
+            return true;
+        }
     }
 
-    return true;
+    return false;
 }
 
 static void process_kernel_dt() {
@@ -664,101 +668,56 @@
     }
 }
 
-static std::string import_dt_fstab() {
-    std::string fstab;
-    if (!is_dt_compatible() || !is_dt_fstab_compatible()) {
-        return fstab;
+static bool early_mount_one(struct fstab_rec* rec) {
+    if (rec && fs_mgr_is_verified(rec)) {
+        // setup verity and create the dm-XX block device
+        // needed to mount this partition
+        int ret = fs_mgr_setup_verity(rec, false);
+        if (ret == FS_MGR_SETUP_VERITY_FAIL) {
+            PLOG(ERROR) << "early_mount: Failed to setup verity for '" << rec->mount_point << "'";
+            return false;
+        }
+
+        // The exact block device name is added as a mount source by
+        // fs_mgr_setup_verity() in ->blk_device as "/dev/block/dm-XX"
+        // We create that device by running coldboot on /sys/block/dm-XX
+        std::string dm_device(basename(rec->blk_device));
+        std::string syspath = StringPrintf("/sys/block/%s", dm_device.c_str());
+        device_init(syspath.c_str(), [&](uevent* uevent) -> coldboot_action_t {
+            if (uevent->device_name && !strcmp(dm_device.c_str(), uevent->device_name)) {
+                LOG(VERBOSE) << "early_mount: creating dm-verity device : " << dm_device;
+                return COLDBOOT_STOP;
+            }
+            return COLDBOOT_CONTINUE;
+        });
     }
 
-    std::string fstabdir_name = StringPrintf("%s/fstab", android_dt_dir);
-    std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir);
-    if (!fstabdir) return fstab;
-
-    dirent* dp;
-    while ((dp = readdir(fstabdir.get())) != NULL) {
-        // skip over name and compatible
-        if (dp->d_type != DT_DIR) {
-            continue;
-        }
-
-        // skip if its not 'vendor', 'odm' or 'system'
-        if (strcmp(dp->d_name, "odm") && strcmp(dp->d_name, "system") &&
-            strcmp(dp->d_name, "vendor")) {
-            continue;
-        }
-
-        // create <dev> <mnt_point>  <type>  <mnt_flags>  <fsmgr_flags>\n
-        std::vector<std::string> fstab_entry;
-        std::string file_name;
-        std::string value;
-        file_name = StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
-        if (!android::base::ReadFileToString(file_name, &value)) {
-            LOG(ERROR) << "dt_fstab: Failed to find device for partition " << dp->d_name;
-            fstab.clear();
-            break;
-        }
-        // trim the terminating '\0' out
-        value.resize(value.size() - 1);
-        fstab_entry.push_back(value);
-        fstab_entry.push_back(StringPrintf("/%s", dp->d_name));
-
-        file_name = StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name);
-        if (!android::base::ReadFileToString(file_name, &value)) {
-            LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
-            fstab.clear();
-            break;
-        }
-        value.resize(value.size() - 1);
-        fstab_entry.push_back(value);
-
-        file_name = StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
-        if (!android::base::ReadFileToString(file_name, &value)) {
-            LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
-            fstab.clear();
-            break;
-        }
-        value.resize(value.size() - 1);
-        fstab_entry.push_back(value);
-
-        file_name = StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
-        if (!android::base::ReadFileToString(file_name, &value)) {
-            LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
-            fstab.clear();
-            break;
-        }
-        value.resize(value.size() - 1);
-        fstab_entry.push_back(value);
-
-        fstab += android::base::Join(fstab_entry, " ");
-        fstab += '\n';
+    if (rec && fs_mgr_do_mount_one(rec)) {
+        PLOG(ERROR) << "early_mount: Failed to mount '" << rec->mount_point << "'";
+        return false;
     }
 
-    return fstab;
+    return true;
 }
 
 /* Early mount vendor and ODM partitions. The fstab is read from device-tree. */
 static bool early_mount() {
-    std::string fstab = import_dt_fstab();
-    if (fstab.empty()) {
-        LOG(INFO) << "Early mount skipped (missing fstab in device tree)";
+    // first check if device tree fstab entries are compatible
+    if (!is_dt_fstab_compatible()) {
+        LOG(INFO) << "Early mount skipped (missing/incompatible fstab in device tree)";
         return true;
     }
 
-    std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
-        fmemopen(static_cast<void*>(const_cast<char*>(fstab.c_str())), fstab.length(), "r"), fclose);
-    if (!fstab_file) {
-        PLOG(ERROR) << "Early mount failed to open fstab file in memory";
-        return false;
-    }
-
-    std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> tab(
-        fs_mgr_read_fstab_file(fstab_file.get()), fs_mgr_free_fstab);
+    std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> tab(
+        fs_mgr_read_fstab_dt(), fs_mgr_free_fstab);
     if (!tab) {
-        LOG(ERROR) << "Early mount fsmgr failed to load fstab from kernel:" << std::endl << fstab;
+        LOG(ERROR) << "Early mount failed to read fstab from device tree";
         return false;
     }
 
     // find out fstab records for odm, system and vendor
+    // TODO: add std::map<std::string, fstab_rec*> so all required information about
+    // them can be gathered at once in a single loop
     fstab_rec* odm_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/odm");
     fstab_rec* system_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/system");
     fstab_rec* vendor_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/vendor");
@@ -767,13 +726,41 @@
         return true;
     }
 
+    // don't allow verifyatboot for early mounted partitions
+    if ((odm_rec && fs_mgr_is_verifyatboot(odm_rec)) ||
+        (system_rec && fs_mgr_is_verifyatboot(system_rec)) ||
+        (vendor_rec && fs_mgr_is_verifyatboot(vendor_rec))) {
+        LOG(ERROR) << "Early mount partitions can't be verified at boot";
+        return false;
+    }
+
     // assume A/B device if we find 'slotselect' in any fstab entry
     bool is_ab = ((odm_rec && fs_mgr_is_slotselect(odm_rec)) ||
                   (system_rec && fs_mgr_is_slotselect(system_rec)) ||
                   (vendor_rec && fs_mgr_is_slotselect(vendor_rec)));
+
+    // check for verified partitions
+    bool need_verity = ((odm_rec && fs_mgr_is_verified(odm_rec)) ||
+                        (system_rec && fs_mgr_is_verified(system_rec)) ||
+                        (vendor_rec && fs_mgr_is_verified(vendor_rec)));
+
+    // check if verity metadata is on a separate partition and get partition
+    // name from the end of the ->verity_loc path. verity state is not partition
+    // specific, so there must be only 1 additional partition that carries
+    // verity state.
+    std::string meta_partition;
+    if (odm_rec && odm_rec->verity_loc) {
+        meta_partition = basename(odm_rec->verity_loc);
+    } else if (system_rec && system_rec->verity_loc) {
+        meta_partition = basename(system_rec->verity_loc);
+    } else if (vendor_rec && vendor_rec->verity_loc) {
+        meta_partition = basename(vendor_rec->verity_loc);
+    }
+
     bool found_odm = !odm_rec;
     bool found_system = !system_rec;
     bool found_vendor = !vendor_rec;
+    bool found_meta = meta_partition.empty();
     int count_odm = 0, count_vendor = 0, count_system = 0;
 
     // create the devices we need..
@@ -802,9 +789,7 @@
 
                 // wait twice for A/B-ed partitions
                 count_odm++;
-                if (!is_ab) {
-                    found_odm = true;
-                } else if (count_odm == 2) {
+                if (!is_ab || count_odm == 2) {
                     found_odm = true;
                 }
 
@@ -813,9 +798,7 @@
                 LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
 
                 count_system++;
-                if (!is_ab) {
-                    found_system = true;
-                } else if (count_system == 2) {
+                if (!is_ab || count_system == 2) {
                     found_system = true;
                 }
 
@@ -823,13 +806,15 @@
             } else if (!found_vendor && !strncmp(uevent->partition_name, "vendor", 6)) {
                 LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
                 count_vendor++;
-                if (!is_ab) {
-                    found_vendor = true;
-                } else if (count_vendor == 2) {
+                if (!is_ab || count_vendor == 2) {
                     found_vendor = true;
                 }
 
                 create_this_node = true;
+            } else if (!found_meta && (meta_partition == uevent->partition_name)) {
+                LOG(VERBOSE) <<  "early_mount: found (" << uevent->partition_name << ") partition";
+                found_meta = true;
+                create_this_node = true;
             }
         }
 
@@ -837,7 +822,7 @@
         // node and stop coldboot. If this is a prefix matched
         // partition, create device node and continue. For everything
         // else skip the device node
-        if (found_odm && found_system && found_vendor) {
+        if (found_meta && found_odm && found_system && found_vendor) {
             ret = COLDBOOT_STOP;
         } else if (create_this_node) {
             ret = COLDBOOT_CREATE;
@@ -848,24 +833,20 @@
         return ret;
     });
 
-    // TODO: add support to mount partitions w/ verity
-
-    int ret = 0;
-    if (odm_rec &&
-        (ret = fs_mgr_do_mount(tab.get(), odm_rec->mount_point, odm_rec->blk_device, NULL))) {
-        PLOG(ERROR) << "early_mount: fs_mgr_do_mount returned error for mounting odm";
-        return false;
+    if (need_verity) {
+        // create /dev/device mapper
+        device_init("/sys/devices/virtual/misc/device-mapper",
+                    [&](uevent* uevent) -> coldboot_action_t { return COLDBOOT_STOP; });
     }
 
-    if (vendor_rec &&
-        (ret = fs_mgr_do_mount(tab.get(), vendor_rec->mount_point, vendor_rec->blk_device, NULL))) {
-        PLOG(ERROR) << "early_mount: fs_mgr_do_mount returned error for mounting vendor";
-        return false;
-    }
+    bool success = true;
+    if (odm_rec && !(success = early_mount_one(odm_rec))) goto done;
+    if (system_rec && !(success = early_mount_one(system_rec))) goto done;
+    if (vendor_rec && !(success = early_mount_one(vendor_rec))) goto done;
 
+done:
     device_close();
-
-    return true;
+    return success;
 }
 
 int main(int argc, char** argv) {
diff --git a/libutils/include/utils/Condition.h b/libutils/include/utils/Condition.h
index 25a53aa..2c80acd 100644
--- a/libutils/include/utils/Condition.h
+++ b/libutils/include/utils/Condition.h
@@ -86,19 +86,22 @@
 
 #if !defined(_WIN32)
 
-inline Condition::Condition() {
-    pthread_cond_init(&mCond, NULL);
+inline Condition::Condition() : Condition(PRIVATE) {
 }
 inline Condition::Condition(int type) {
+    pthread_condattr_t attr;
+    pthread_condattr_init(&attr);
+#if defined(__linux__)
+    pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
+#endif
+
     if (type == SHARED) {
-        pthread_condattr_t attr;
-        pthread_condattr_init(&attr);
         pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
-        pthread_cond_init(&mCond, &attr);
-        pthread_condattr_destroy(&attr);
-    } else {
-        pthread_cond_init(&mCond, NULL);
     }
+
+    pthread_cond_init(&mCond, &attr);
+    pthread_condattr_destroy(&attr);
+
 }
 inline Condition::~Condition() {
     pthread_cond_destroy(&mCond);
@@ -109,7 +112,7 @@
 inline status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) {
     struct timespec ts;
 #if defined(__linux__)
-    clock_gettime(CLOCK_REALTIME, &ts);
+    clock_gettime(CLOCK_MONOTONIC, &ts);
 #else // __APPLE__
     // Apple doesn't support POSIX clocks.
     struct timeval t;