Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3cffba1b authored by Yi-Yo Chiang's avatar Yi-Yo Chiang Committed by Automerger Merge Worker
Browse files

Merge "init: Use libfs_mgr kernel cmdline parser" into main am: 63a3f34e

parents 18cea8df 63a3f34e
Loading
Loading
Loading
Loading
+29 −36
Original line number Diff line number Diff line
@@ -17,11 +17,9 @@
#include <algorithm>
#include <iterator>
#include <string>
#include <vector>

#include <android-base/file.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>

#include "fstab_priv.h"
@@ -35,7 +33,7 @@ const std::string& GetAndroidDtDir() {
    static const std::string kAndroidDtDir = [] {
        std::string android_dt_dir;
        if ((GetBootconfig("androidboot.android_dt_dir", &android_dt_dir) ||
             fs_mgr_get_boot_config_from_kernel_cmdline("android_dt_dir", &android_dt_dir)) &&
             GetKernelCmdline("androidboot.android_dt_dir", &android_dt_dir)) &&
            !android_dt_dir.empty()) {
            // Ensure the returned path ends with a /
            if (android_dt_dir.back() != '/') {
@@ -110,13 +108,10 @@ bool GetBootconfig(const std::string& key, std::string* out) {
    return GetBootconfigFromString(bootconfig, key, out);
}

}  // namespace fs_mgr
}  // namespace android

std::vector<std::pair<std::string, std::string>> fs_mgr_parse_cmdline(const std::string& cmdline) {
void ImportKernelCmdlineFromString(const std::string& cmdline,
                                   const std::function<void(std::string, std::string)>& fn) {
    static constexpr char quote = '"';

    std::vector<std::pair<std::string, std::string>> result;
    size_t base = 0;
    while (true) {
        // skip quoted spans
@@ -135,48 +130,46 @@ std::vector<std::pair<std::string, std::string>> fs_mgr_parse_cmdline(const std:
        if (equal_sign == piece.npos) {
            if (!piece.empty()) {
                // no difference between <key> and <key>=
                result.emplace_back(std::move(piece), "");
                fn(std::move(piece), "");
            }
        } else {
            result.emplace_back(piece.substr(0, equal_sign), piece.substr(equal_sign + 1));
            fn(piece.substr(0, equal_sign), piece.substr(equal_sign + 1));
        }
        if (found == cmdline.npos) break;
        base = found + 1;
    }

    return result;
}

bool fs_mgr_get_boot_config_from_kernel(const std::string& cmdline, const std::string& android_key,
                                        std::string* out_val) {
    FSTAB_CHECK(out_val != nullptr);

    const std::string cmdline_key("androidboot." + android_key);
    for (const auto& [key, value] : fs_mgr_parse_cmdline(cmdline)) {
        if (key == cmdline_key) {
            *out_val = value;
            return true;
bool GetKernelCmdlineFromString(const std::string& cmdline, const std::string& key,
                                std::string* out) {
    bool found = false;
    ImportKernelCmdlineFromString(cmdline, [&](std::string config_key, std::string value) {
        if (!found && config_key == key) {
            *out = std::move(value);
            found = true;
        }
    });
    return found;
}

    *out_val = "";
    return false;
void ImportKernelCmdline(const std::function<void(std::string, std::string)>& fn) {
    std::string cmdline;
    android::base::ReadFileToString("/proc/cmdline", &cmdline);
    ImportKernelCmdlineFromString(android::base::Trim(cmdline), fn);
}

// Tries to get the given boot config value from kernel cmdline.
// Returns true if successfully found, false otherwise.
bool fs_mgr_get_boot_config_from_kernel_cmdline(const std::string& key, std::string* out_val) {
bool GetKernelCmdline(const std::string& key, std::string* out) {
    std::string cmdline;
    if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) return false;
    if (!cmdline.empty() && cmdline.back() == '\n') {
        cmdline.pop_back();
    }
    return fs_mgr_get_boot_config_from_kernel(cmdline, key, out_val);
    android::base::ReadFileToString("/proc/cmdline", &cmdline);
    return GetKernelCmdlineFromString(android::base::Trim(cmdline), key, out);
}

// Tries to get the boot config value in device tree, properties and
// kernel cmdline (in that order).  Returns 'true' if successfully
// found, 'false' otherwise.
}  // namespace fs_mgr
}  // namespace android

// Tries to get the boot config value in device tree, properties, kernel bootconfig and kernel
// cmdline (in that order).
// Returns 'true' if successfully found, 'false' otherwise.
bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val) {
    FSTAB_CHECK(out_val != nullptr);

@@ -204,7 +197,7 @@ bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val) {
    }

    // finally, fallback to kernel cmdline, properties may not be ready yet
    if (fs_mgr_get_boot_config_from_kernel_cmdline(key, out_val)) {
    if (android::fs_mgr::GetKernelCmdline(config_key, out_val)) {
        return true;
    }

+11 −17
Original line number Diff line number Diff line
@@ -863,11 +863,11 @@ const FstabEntry* GetEntryForMountPoint(const Fstab* fstab, const std::string& p
}

std::set<std::string> GetBootDevices() {
    std::set<std::string> boot_devices;
    // First check bootconfig, then kernel commandline, then the device tree
    std::string value;
    if (GetBootconfig("androidboot.boot_devices", &value) ||
        GetBootconfig("androidboot.boot_device", &value)) {
        std::set<std::string> boot_devices;
        // split by spaces and trim the trailing comma.
        for (std::string_view device : android::base::Split(value, " ")) {
            base::ConsumeSuffix(&device, ",");
@@ -876,26 +876,20 @@ std::set<std::string> GetBootDevices() {
        return boot_devices;
    }

    std::string dt_file_name = GetAndroidDtDir() + "boot_devices";
    if (fs_mgr_get_boot_config_from_kernel_cmdline("boot_devices", &value) ||
        ReadDtFile(dt_file_name, &value)) {
        auto boot_devices = Split(value, ",");
        return std::set<std::string>(boot_devices.begin(), boot_devices.end());
    const std::string dt_file_name = GetAndroidDtDir() + "boot_devices";
    if (GetKernelCmdline("androidboot.boot_devices", &value) || ReadDtFile(dt_file_name, &value)) {
        auto boot_devices_list = Split(value, ",");
        return {boot_devices_list.begin(), boot_devices_list.end()};
    }

    std::string cmdline;
    if (android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
        std::set<std::string> boot_devices;
        const std::string cmdline_key = "androidboot.boot_device";
        for (const auto& [key, value] : fs_mgr_parse_cmdline(cmdline)) {
            if (key == cmdline_key) {
                boot_devices.emplace(value);
            }
    ImportKernelCmdline([&](std::string key, std::string value) {
        if (key == "androidboot.boot_device") {
            boot_devices.emplace(std::move(value));
        }
    });
    if (!boot_devices.empty()) {
        return boot_devices;
    }
    }

    // Fallback to extract boot devices from fstab.
    Fstab fstab;
+6 −6
Original line number Diff line number Diff line
@@ -18,17 +18,11 @@

#include <functional>
#include <string>
#include <utility>
#include <vector>

#include <fstab/fstab.h>

// Do not include logging_macros.h here as this header is used by fs_mgr, too.

std::vector<std::pair<std::string, std::string>> fs_mgr_parse_cmdline(const std::string& cmdline);
bool fs_mgr_get_boot_config_from_kernel(const std::string& cmdline, const std::string& key,
                                        std::string* out_val);
bool fs_mgr_get_boot_config_from_kernel_cmdline(const std::string& key, std::string* out_val);
bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val);

bool fs_mgr_update_for_slotselect(android::fs_mgr::Fstab* fstab);
@@ -48,5 +42,11 @@ void ImportBootconfigFromString(const std::string& bootconfig,
bool GetBootconfigFromString(const std::string& bootconfig, const std::string& key,
                             std::string* out);

void ImportKernelCmdlineFromString(const std::string& cmdline,
                                   const std::function<void(std::string, std::string)>& fn);

bool GetKernelCmdlineFromString(const std::string& cmdline, const std::string& key,
                                std::string* out);

}  // namespace fs_mgr
}  // namespace android
+8 −0
Original line number Diff line number Diff line
@@ -137,5 +137,13 @@ void ImportBootconfig(const std::function<void(std::string, std::string)>& fn);
// Otherwise returns false and |*out| is not modified.
bool GetBootconfig(const std::string& key, std::string* out);

// Import the kernel cmdline by calling the callback |fn| with each key-value pair.
void ImportKernelCmdline(const std::function<void(std::string, std::string)>& fn);

// Get the kernel cmdline value for |key|.
// Returns true if |key| is found in the kernel cmdline.
// Otherwise returns false and |*out| is not modified.
bool GetKernelCmdline(const std::string& key, std::string* out);

}  // namespace fs_mgr
}  // namespace android
+25 −18
Original line number Diff line number Diff line
@@ -224,23 +224,32 @@ bool CompareFlags(FstabEntry::FsMgrFlags& lhs, FstabEntry::FsMgrFlags& rhs) {

}  // namespace

TEST(fs_mgr, fs_mgr_parse_cmdline) {
    EXPECT_EQ(result_space, fs_mgr_parse_cmdline(cmdline));
TEST(fs_mgr, ImportKernelCmdline) {
    std::vector<std::pair<std::string, std::string>> result;
    ImportKernelCmdlineFromString(
            cmdline, [&](std::string key, std::string value) { result.emplace_back(key, value); });
    EXPECT_THAT(result, ContainerEq(result_space));
}

TEST(fs_mgr, fs_mgr_get_boot_config_from_kernel_cmdline) {
TEST(fs_mgr, GetKernelCmdline) {
    std::string content;
    for (const auto& entry : result_space) {
        static constexpr char androidboot[] = "androidboot.";
        if (!android::base::StartsWith(entry.first, androidboot)) continue;
        auto key = entry.first.substr(strlen(androidboot));
        EXPECT_TRUE(fs_mgr_get_boot_config_from_kernel(cmdline, key, &content)) << " for " << key;
        EXPECT_EQ(entry.second, content);
    for (const auto& [key, value] : result_space) {
        EXPECT_TRUE(GetKernelCmdlineFromString(cmdline, key, &content)) << " for " << key;
        EXPECT_EQ(content, value);
    }
    EXPECT_FALSE(fs_mgr_get_boot_config_from_kernel(cmdline, "vbmeta.avb_versio", &content));
    EXPECT_TRUE(content.empty()) << content;
    EXPECT_FALSE(fs_mgr_get_boot_config_from_kernel(cmdline, "nospace", &content));
    EXPECT_TRUE(content.empty()) << content;

    const std::string kUnmodifiedToken = "<UNMODIFIED>";
    content = kUnmodifiedToken;
    EXPECT_FALSE(GetKernelCmdlineFromString(cmdline, "", &content));
    EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden";

    content = kUnmodifiedToken;
    EXPECT_FALSE(GetKernelCmdlineFromString(cmdline, "androidboot.vbmeta.avb_versio", &content));
    EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden";

    content = kUnmodifiedToken;
    EXPECT_FALSE(GetKernelCmdlineFromString(bootconfig, "androidboot.nospace", &content));
    EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden";
}

TEST(fs_mgr, ImportBootconfig) {
@@ -260,17 +269,15 @@ TEST(fs_mgr, GetBootconfig) {

    const std::string kUnmodifiedToken = "<UNMODIFIED>";
    content = kUnmodifiedToken;
    EXPECT_FALSE(android::fs_mgr::GetBootconfigFromString(bootconfig, "", &content));
    EXPECT_FALSE(GetBootconfigFromString(bootconfig, "", &content));
    EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden";

    content = kUnmodifiedToken;
    EXPECT_FALSE(android::fs_mgr::GetBootconfigFromString(
            bootconfig, "androidboot.vbmeta.avb_versio", &content));
    EXPECT_FALSE(GetBootconfigFromString(bootconfig, "androidboot.vbmeta.avb_versio", &content));
    EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden";

    content = kUnmodifiedToken;
    EXPECT_FALSE(
            android::fs_mgr::GetBootconfigFromString(bootconfig, "androidboot.nospace", &content));
    EXPECT_FALSE(GetBootconfigFromString(bootconfig, "androidboot.nospace", &content));
    EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden";
}

Loading