fs_mgr: add a generic fs_mgr_get_boot_config internal API

depending on when fs_mgr is trying to read the configuration passed into
the kernel commandline, it may be able to read it successfully.
Specially in the case when init has not initialized properties.

This change adds a new fs_mgr_get_boot_config() API to be used by all
fs_mgr code in order to get filesystem parameters specified in kernel
command line or device tree. This way the fs_mgr code doesn't have to
handle the "early" cases separately anywhere.

Test:
Tested angler boot with both /system and /vendor mounted in init
first stage.
Tested sailfish to make sure /vendor can be continued to be
mounted early without verity

Change-Id: I9a44cdfc32681f714c5d73ae55c3deda95c02545
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_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..ae442cf
--- /dev/null
+++ b/fs_mgr/fs_mgr_boot_config.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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
+    static const std::string android_dt_dir("/proc/device-tree/firmware/android");
+    std::string file_name = android_dt_dir + "/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 = android_dt_dir + "/" + 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_priv.h b/fs_mgr/fs_mgr_priv.h
index 79c27c4..478c145 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
diff --git a/fs_mgr/fs_mgr_priv_boot_config.h b/fs_mgr/fs_mgr_priv_boot_config.h
new file mode 100644
index 0000000..74bb5eb
--- /dev/null
+++ b/fs_mgr/fs_mgr_priv_boot_config.h
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+#ifndef __CORE_FS_MGR_PRIV_BOOTCONFIG_H
+#define __CORE_FS_MGR_PRIV_BOOTCONFIG_H
+
+#include <sys/cdefs.h>
+#include <string>
+
+bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val);
+
+#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 d72ac73..2c9b0a9 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -657,7 +657,6 @@
 
 static int load_verity_state(struct fstab_rec *fstab, int *mode)
 {
-    char propbuf[PROPERTY_VALUE_MAX];
     int match = 0;
     off64_t offset = 0;
 
@@ -665,10 +664,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;