Merge changes from topic 'avb-early-mount' am: d7381375bb
am: 04989a7a4b

Change-Id: I45d89c806076842ee75a772b1a8bbba2157eb46c
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 28da9db..ea9cb37 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -31,7 +31,10 @@
 #include <time.h>
 #include <unistd.h>
 
+#include <memory>
+
 #include <android-base/file.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/unique_fd.h>
 #include <cutils/android_reboot.h>
@@ -50,6 +53,7 @@
 #include "fs_mgr.h"
 #include "fs_mgr_avb.h"
 #include "fs_mgr_priv.h"
+#include "fs_mgr_priv_dm_ioctl.h"
 
 #define KEY_LOC_PROP   "ro.crypto.keyfile.userdata"
 #define KEY_IN_FOOTER  "footer"
@@ -1258,3 +1262,97 @@
 
     return 0;
 }
+
+bool fs_mgr_load_verity_state(int* mode) {
+    /* return the default mode, unless any of the verified partitions are in
+     * logging mode, in which case return that */
+    *mode = VERITY_MODE_DEFAULT;
+
+    std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
+                                                               fs_mgr_free_fstab);
+    if (!fstab) {
+        LERROR << "Failed to read default fstab";
+        return false;
+    }
+
+    for (int i = 0; i < fstab->num_entries; i++) {
+        if (fs_mgr_is_avb(&fstab->recs[i])) {
+            *mode = VERITY_MODE_RESTART;  // avb only supports restart mode.
+            break;
+        } else if (!fs_mgr_is_verified(&fstab->recs[i])) {
+            continue;
+        }
+
+        int current;
+        if (load_verity_state(&fstab->recs[i], &current) < 0) {
+            continue;
+        }
+        if (current != VERITY_MODE_DEFAULT) {
+            *mode = current;
+            break;
+        }
+    }
+
+    return true;
+}
+
+bool fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback) {
+    if (!callback) {
+        return false;
+    }
+
+    int mode;
+    if (!fs_mgr_load_verity_state(&mode)) {
+        return false;
+    }
+
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC)));
+    if (fd == -1) {
+        PERROR << "Error opening device mapper";
+        return false;
+    }
+
+    std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
+                                                               fs_mgr_free_fstab);
+    if (!fstab) {
+        LERROR << "Failed to read default fstab";
+        return false;
+    }
+
+    alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
+    struct dm_ioctl* io = (struct dm_ioctl*)buffer;
+    bool system_root = android::base::GetProperty("ro.build.system_root_image", "") == "true";
+
+    for (int i = 0; i < fstab->num_entries; i++) {
+        if (!fs_mgr_is_verified(&fstab->recs[i]) && !fs_mgr_is_avb(&fstab->recs[i])) {
+            continue;
+        }
+
+        std::string mount_point;
+        if (system_root && !strcmp(fstab->recs[i].mount_point, "/")) {
+            mount_point = "system";
+        } else {
+            mount_point = basename(fstab->recs[i].mount_point);
+        }
+
+        fs_mgr_verity_ioctl_init(io, mount_point, 0);
+
+        const char* status;
+        if (ioctl(fd, DM_TABLE_STATUS, io)) {
+            if (fstab->recs[i].fs_mgr_flags & MF_VERIFYATBOOT) {
+                status = "V";
+            } else {
+                PERROR << "Failed to query DM_TABLE_STATUS for " << mount_point.c_str();
+                continue;
+            }
+        }
+
+        status = &buffer[io->data_start + sizeof(struct dm_target_spec)];
+
+        if (*status == 'C' || *status == 'V') {
+            callback(&fstab->recs[i], mount_point.c_str(), mode, *status);
+        }
+    }
+
+    return true;
+}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index dedffd8..c985462 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -115,5 +115,6 @@
 bool fs_mgr_update_for_slotselect(struct fstab *fstab);
 bool is_dt_compatible();
 bool is_device_secure();
+int load_verity_state(struct fstab_rec* fstab, int* mode);
 
 #endif /* __CORE_FS_MGR_PRIV_H */
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 8c7a8ca..0bf173b 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -653,8 +653,7 @@
                 offset);
 }
 
-static int load_verity_state(struct fstab_rec *fstab, int *mode)
-{
+int load_verity_state(struct fstab_rec* fstab, int* mode) {
     int match = 0;
     off64_t offset = 0;
 
@@ -690,129 +689,6 @@
     return read_verity_state(fstab->verity_loc, offset, mode);
 }
 
-int fs_mgr_load_verity_state(int *mode)
-{
-    int rc = -1;
-    int i;
-    int current;
-    struct fstab *fstab = NULL;
-
-    /* return the default mode, unless any of the verified partitions are in
-     * logging mode, in which case return that */
-    *mode = VERITY_MODE_DEFAULT;
-
-    fstab = fs_mgr_read_fstab_default();
-    if (!fstab) {
-        LERROR << "Failed to read default fstab";
-        goto out;
-    }
-
-    for (i = 0; i < fstab->num_entries; i++) {
-        if (!fs_mgr_is_verified(&fstab->recs[i])) {
-            continue;
-        }
-
-        rc = load_verity_state(&fstab->recs[i], &current);
-        if (rc < 0) {
-            continue;
-        }
-
-        if (current != VERITY_MODE_DEFAULT) {
-            *mode = current;
-            break;
-        }
-    }
-
-    rc = 0;
-
-out:
-    if (fstab) {
-        fs_mgr_free_fstab(fstab);
-    }
-
-    return rc;
-}
-
-int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback)
-{
-    alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
-    bool system_root = false;
-    std::string mount_point;
-    char propbuf[PROPERTY_VALUE_MAX];
-    const char *status;
-    int fd = -1;
-    int i;
-    int mode;
-    int rc = -1;
-    struct dm_ioctl *io = (struct dm_ioctl *) buffer;
-    struct fstab *fstab = NULL;
-
-    if (!callback) {
-        return -1;
-    }
-
-    if (fs_mgr_load_verity_state(&mode) == -1) {
-        return -1;
-    }
-
-    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.build.system_root_image", propbuf, "");
-    system_root = !strcmp(propbuf, "true");
-    fstab = fs_mgr_read_fstab_default();
-    if (!fstab) {
-        LERROR << "Failed to read default fstab";
-        goto out;
-    }
-
-    for (i = 0; i < fstab->num_entries; i++) {
-        if (!fs_mgr_is_verified(&fstab->recs[i])) {
-            continue;
-        }
-
-        if (system_root && !strcmp(fstab->recs[i].mount_point, "/")) {
-            mount_point = "system";
-        } else {
-            mount_point = basename(fstab->recs[i].mount_point);
-        }
-
-        fs_mgr_verity_ioctl_init(io, mount_point, 0);
-
-        if (ioctl(fd, DM_TABLE_STATUS, io)) {
-            if (fstab->recs[i].fs_mgr_flags & MF_VERIFYATBOOT) {
-                status = "V";
-            } else {
-                PERROR << "Failed to query DM_TABLE_STATUS for "
-                       << mount_point.c_str();
-                continue;
-            }
-        }
-
-        status = &buffer[io->data_start + sizeof(struct dm_target_spec)];
-
-        if (*status == 'C' || *status == 'V') {
-            callback(&fstab->recs[i], mount_point.c_str(), mode, *status);
-        }
-    }
-
-    rc = 0;
-
-out:
-    if (fstab) {
-        fs_mgr_free_fstab(fstab);
-    }
-
-    if (fd) {
-        close(fd);
-    }
-
-    return rc;
-}
-
 static void update_verity_table_blk_device(char *blk_device, char **table)
 {
     std::string result, word;
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index cea70b4..12db672 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -113,8 +113,8 @@
 int fs_mgr_unmount_all(struct fstab *fstab);
 int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc,
                           char *real_blk_device, int size);
-int fs_mgr_load_verity_state(int *mode);
-int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback);
+bool fs_mgr_load_verity_state(int* mode);
+bool fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback);
 int fs_mgr_add_entry(struct fstab *fstab,
                      const char *mount_point, const char *fs_type,
                      const char *blk_device);
diff --git a/init/Android.mk b/init/Android.mk
index 7e9b613..c9bf9fc 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -111,8 +111,8 @@
     libfec_rs \
     libsquashfs_utils \
     liblogwrap \
-    libcutils \
     libext4_utils \
+    libcutils \
     libbase \
     libc \
     libselinux \
diff --git a/init/builtins.cpp b/init/builtins.cpp
index e1d9b94..2327cdf 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -677,11 +677,11 @@
 
 static int do_verity_load_state(const std::vector<std::string>& args) {
     int mode = -1;
-    int rc = fs_mgr_load_verity_state(&mode);
-    if (rc == 0 && mode != VERITY_MODE_DEFAULT) {
+    bool loaded = fs_mgr_load_verity_state(&mode);
+    if (loaded && mode != VERITY_MODE_DEFAULT) {
         ActionManager::GetInstance().QueueEventTrigger("verity-logging");
     }
-    return rc;
+    return loaded ? 0 : 1;
 }
 
 static void verity_update_property(fstab_rec *fstab, const char *mount_point,
@@ -691,7 +691,7 @@
 }
 
 static int do_verity_update_state(const std::vector<std::string>& args) {
-    return fs_mgr_update_verity_state(verity_update_property);
+    return fs_mgr_update_verity_state(verity_update_property) ? 0 : 1;
 }
 
 static int do_write(const std::vector<std::string>& args) {
diff --git a/init/init.cpp b/init/init.cpp
index 543f38e..6c09c99 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -61,6 +61,7 @@
 #include "bootchart.h"
 #include "devices.h"
 #include "fs_mgr.h"
+#include "fs_mgr_avb.h"
 #include "import_parser.h"
 #include "init_parser.h"
 #include "keychords.h"
@@ -482,42 +483,73 @@
     }
 }
 
-static constexpr char android_dt_dir[] = "/proc/device-tree/firmware/android";
-
-static bool is_dt_compatible() {
-    std::string dt_value;
-    std::string file_name = StringPrintf("%s/compatible", android_dt_dir);
-
-    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") {
+/* Reads the content of device tree file into dt_value.
+ * Returns true if the read is success, false otherwise.
+ */
+static bool read_dt_file(const std::string& file_name, std::string* dt_value) {
+    if (android::base::ReadFileToString(file_name, dt_value)) {
+        if (!dt_value->empty()) {
+            dt_value->pop_back();  // Trim the trailing '\0' out.
             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");
+static const std::string kAndroidDtDir("/proc/device-tree/firmware/android/");
 
-    if (android::base::ReadFileToString(file_name, &dt_value)) {
-        dt_value.resize(dt_value.size() - 1);
-        if (dt_value == "android,fstab") {
+static bool is_dt_value_expected(const std::string& dt_file_suffix,
+                                 const std::string& expected_value) {
+    std::string dt_value;
+    std::string file_name = kAndroidDtDir + dt_file_suffix;
+
+    if (read_dt_file(file_name, &dt_value)) {
+        if (dt_value == expected_value) {
             return true;
         }
     }
-
     return false;
 }
 
+static inline bool is_dt_compatible() {
+    return is_dt_value_expected("compatible", "android,firmware");
+}
+
+static inline bool is_dt_fstab_compatible() {
+    return is_dt_value_expected("fstab/compatible", "android,fstab");
+}
+
+static inline bool is_dt_vbmeta_compatible() {
+    return is_dt_value_expected("vbmeta/compatible", "android,vbmeta");
+}
+
+// Gets the vbmeta config from device tree. Specifically, the 'parts' and 'by_name_prefix'.
+// /{
+//     firmware {
+//         android {
+//             vbmeta {
+//                 compatible = "android,vbmeta";
+//                 parts = "vbmeta,boot,system,vendor"
+//                 by_name_prefix="/dev/block/platform/soc.0/f9824900.sdhci/by-name/"
+//             };
+//         };
+//     };
+//  }
+static bool get_vbmeta_config_from_dt(std::string* vbmeta_partitions,
+                                      std::string* device_file_by_name_prefix) {
+    std::string file_name = kAndroidDtDir + "vbmeta/parts";
+    if (!read_dt_file(file_name, vbmeta_partitions)) return false;
+
+    file_name = kAndroidDtDir + "vbmeta/by_name_prefix";
+    if (!read_dt_file(file_name, device_file_by_name_prefix)) return false;
+
+    return true;
+}
+
 static void process_kernel_dt() {
     if (!is_dt_compatible()) return;
 
-    std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dt_dir), closedir);
+    std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(kAndroidDtDir.c_str()), closedir);
     if (!dir) return;
 
     std::string dt_file;
@@ -527,7 +559,7 @@
             continue;
         }
 
-        std::string file_name = StringPrintf("%s/%s", android_dt_dir, dp->d_name);
+        std::string file_name = kAndroidDtDir + dp->d_name;
 
         android::base::ReadFileToString(file_name, &dt_file);
         std::replace(dt_file.begin(), dt_file.end(), ',', '.');
@@ -920,38 +952,100 @@
     }
 }
 
-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 << "'";
+// Creates "/dev/block/dm-XX" for dm-verity by running coldboot on /sys/block/dm-XX.
+static void device_init_dm_device(const std::string& dm_device) {
+    const std::string device_name(basename(dm_device.c_str()));
+    const std::string syspath = "/sys/block/" + device_name;
+
+    device_init(syspath.c_str(), [&](uevent* uevent) -> coldboot_action_t {
+        if (uevent->device_name && device_name == uevent->device_name) {
+            LOG(VERBOSE) << "early_mount: creating dm-verity device : " << dm_device;
+            return COLDBOOT_STOP;
+        }
+        return COLDBOOT_CONTINUE;
+    });
+    device_close();
+}
+
+static bool vboot_1_0_mount_partitions(const std::vector<fstab_rec*>& fstab_recs) {
+    if (fstab_recs.empty()) return false;
+
+    for (auto rec : fstab_recs) {
+        bool need_create_dm_device = false;
+        if (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 /* wait_for_verity_dev */);
+            if (ret == FS_MGR_SETUP_VERITY_DISABLED) {
+                LOG(INFO) << "verity disabled for '" << rec->mount_point << "'";
+            } else if (ret == FS_MGR_SETUP_VERITY_SUCCESS) {
+                need_create_dm_device = true;
+            } else {
+                PLOG(ERROR) << "early_mount: failed to setup verity for '" << rec->mount_point
+                            << "'";
+                return false;
+            }
+        }
+        if (need_create_dm_device) {
+            // The exact block device name (rec->blk_device) is changed to "/dev/block/dm-XX".
+            // Need to create it because ueventd isn't started during early mount.
+            device_init_dm_device(rec->blk_device);
+        }
+        if (fs_mgr_do_mount_one(rec)) {
+            PLOG(ERROR) << "early_mount: failed to mount '" << 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;
-        });
-    }
-
-    if (rec && fs_mgr_do_mount_one(rec)) {
-        PLOG(ERROR) << "early_mount: Failed to mount '" << rec->mount_point << "'";
-        return false;
     }
 
     return true;
 }
 
+static bool vboot_2_0_mount_partitions(const std::vector<fstab_rec*>& fstab_recs,
+                                       const std::string& device_file_by_name_prefix) {
+    if (fstab_recs.empty()) return false;
+
+    FsManagerAvbUniquePtr avb_handle = FsManagerAvbHandle::Open(device_file_by_name_prefix);
+    if (!avb_handle) {
+        LOG(INFO) << "Failed to Open FsManagerAvbHandle";
+        return false;
+    }
+
+    for (auto rec : fstab_recs) {
+        bool need_create_dm_device = false;
+        if (fs_mgr_is_avb(rec)) {
+            if (avb_handle->AvbHashtreeDisabled()) {
+                LOG(INFO) << "avb hashtree disabled for '" << rec->mount_point << "'";
+            } else if (avb_handle->SetUpAvb(rec, false /* wait_for_verity_dev */)) {
+                need_create_dm_device = true;
+            } else {
+                PLOG(ERROR) << "early_mount: failed to set up AVB on partition: '"
+                            << rec->mount_point << "'";
+                return false;
+            }
+        }
+        if (need_create_dm_device) {
+            // The exact block device name (rec->blk_device) is changed to "/dev/block/dm-XX".
+            // Need to create it because ueventd isn't started during early mount.
+            device_init_dm_device(rec->blk_device);
+        }
+        if (fs_mgr_do_mount_one(rec)) {
+            PLOG(ERROR) << "early_mount: failed to mount '" << rec->mount_point << "'";
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static bool mount_early_partitions(const std::vector<fstab_rec*>& fstab_recs,
+                                   const std::string& device_file_by_name_prefix) {
+    if (is_dt_vbmeta_compatible()) {  // AVB (external/avb) is used to setup dm-verity.
+        return vboot_2_0_mount_partitions(fstab_recs, device_file_by_name_prefix);
+    } else {
+        return vboot_1_0_mount_partitions(fstab_recs);
+    }
+}
+
 // Creates devices with uevent->partition_name matching one in the in/out
 // partition_names. Note that the partition_names MUST have A/B suffix
 // when A/B is used. Found partitions will then be removed from the
@@ -994,12 +1088,10 @@
     });
 }
 
-static bool get_early_partitions(const std::vector<fstab_rec*>& early_fstab_recs,
-                                 std::set<std::string>* out_partitions, bool* out_need_verity) {
+static bool vboot_1_0_early_partitions(const std::vector<fstab_rec*>& early_fstab_recs,
+                                       std::set<std::string>* out_partitions,
+                                       bool* out_need_verity) {
     std::string meta_partition;
-    out_partitions->clear();
-    *out_need_verity = false;
-
     for (auto fstab_rec : early_fstab_recs) {
         // don't allow verifyatboot for early mounted partitions
         if (fs_mgr_is_verifyatboot(fstab_rec)) {
@@ -1038,6 +1130,40 @@
     return true;
 }
 
+// a.k.a. AVB (external/avb)
+static bool vboot_2_0_early_partitions(std::set<std::string>* out_partitions, bool* out_need_verity,
+                                       std::string* out_device_file_by_name_prefix) {
+    std::string vbmeta_partitions;
+    if (!get_vbmeta_config_from_dt(&vbmeta_partitions, out_device_file_by_name_prefix)) {
+        return false;
+    }
+    // libavb verifies AVB metadata on all verified partitions at once.
+    // e.g., The vbmeta_partitions will be "vbmeta,boot,system,vendor"
+    // for libavb to verify metadata, even if we only need to early mount /vendor.
+    std::vector<std::string> partitions = android::base::Split(vbmeta_partitions, ",");
+    std::string ab_suffix = fs_mgr_get_slot_suffix();
+    for (const auto& partition : partitions) {
+        out_partitions->emplace(partition + ab_suffix);
+    }
+    *out_need_verity = true;
+    return true;
+}
+
+static bool get_early_partitions(const std::vector<fstab_rec*>& early_fstab_recs,
+                                 std::set<std::string>* out_partitions, bool* out_need_verity,
+                                 std::string* out_device_file_by_name_prefix) {
+    *out_need_verity = false;
+    out_partitions->clear();
+    out_device_file_by_name_prefix->clear();
+
+    if (is_dt_vbmeta_compatible()) {  // AVB (external/avb) is used to setup dm-verity.
+        return vboot_2_0_early_partitions(out_partitions, out_need_verity,
+                                          out_device_file_by_name_prefix);
+    } else {
+        return vboot_1_0_early_partitions(early_fstab_recs, out_partitions, out_need_verity);
+    }
+}
+
 /* Early mount vendor and ODM partitions. The fstab is read from device-tree. */
 static bool early_mount() {
     // skip early mount if we're in recovery mode
@@ -1072,9 +1198,11 @@
     if (early_fstab_recs.empty()) return true;
 
     bool need_verity;
+    std::string device_file_by_name_prefix;
     std::set<std::string> partition_names;
     // partition_names MUST have A/B suffix when A/B is used
-    if (!get_early_partitions(early_fstab_recs, &partition_names, &need_verity)) {
+    if (!get_early_partitions(early_fstab_recs, &partition_names, &need_verity,
+                              &device_file_by_name_prefix)) {
         return false;
     }
 
@@ -1097,10 +1225,9 @@
                     [&](uevent* uevent) -> coldboot_action_t { return COLDBOOT_STOP; });
     }
 
-    for (auto fstab_rec : early_fstab_recs) {
-        if (!early_mount_one(fstab_rec)) goto done;
+    if (mount_early_partitions(early_fstab_recs, device_file_by_name_prefix)) {
+        success = true;
     }
-    success = true;
 
 done:
     device_close();