Support bootconfig in first stage init and fs_mgr
Androidboot parameters are being moved from the kernel commandline to bootconfig. fs_mgr looks for these parameters in properties and falls back to reading directly from /proc/cmdline. So both of these sources are updated for bootconfig. The androidboot parameters from /proc/bootconfig are added as ro.boot properties, and fs_mgr will fall back to searching /proc/bootconfig if it is too early. Test: boot cuttlefish with androidboot.fstab_suffix and androidboot.hardware in bootconfig and not in cmdline. Test: atest CtsFsMgrTestCases Bug: 173815685 Change-Id: Iea36a0da94c26e1aa37d97c576725e0ad77cd3ad
This commit is contained in:
parent
40839a8469
commit
a4ef15bebb
8 changed files with 174 additions and 6 deletions
|
@ -26,7 +26,7 @@
|
|||
|
||||
#include "fs_mgr_priv.h"
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> fs_mgr_parse_boot_config(const std::string& cmdline) {
|
||||
std::vector<std::pair<std::string, std::string>> fs_mgr_parse_cmdline(const std::string& cmdline) {
|
||||
static constexpr char quote = '"';
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> result;
|
||||
|
@ -60,12 +60,50 @@ std::vector<std::pair<std::string, std::string>> fs_mgr_parse_boot_config(const
|
|||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> fs_mgr_parse_proc_bootconfig(
|
||||
const std::string& cmdline) {
|
||||
static constexpr char quote = '"';
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> result;
|
||||
for (auto& line : android::base::Split(cmdline, "\n")) {
|
||||
line.erase(std::remove(line.begin(), line.end(), quote), line.end());
|
||||
auto equal_sign = line.find('=');
|
||||
if (equal_sign == line.npos) {
|
||||
if (!line.empty()) {
|
||||
// no difference between <key> and <key>=
|
||||
result.emplace_back(std::move(line), "");
|
||||
}
|
||||
} else {
|
||||
result.emplace_back(android::base::Trim(line.substr(0, equal_sign)),
|
||||
android::base::Trim(line.substr(equal_sign + 1)));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool fs_mgr_get_boot_config_from_bootconfig(const std::string& bootconfig,
|
||||
const std::string& android_key, std::string* out_val) {
|
||||
FS_MGR_CHECK(out_val != nullptr);
|
||||
|
||||
const std::string bootconfig_key("androidboot." + android_key);
|
||||
for (const auto& [key, value] : fs_mgr_parse_proc_bootconfig(bootconfig)) {
|
||||
if (key == bootconfig_key) {
|
||||
*out_val = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
*out_val = "";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool fs_mgr_get_boot_config_from_kernel(const std::string& cmdline, const std::string& android_key,
|
||||
std::string* out_val) {
|
||||
FS_MGR_CHECK(out_val != nullptr);
|
||||
|
||||
const std::string cmdline_key("androidboot." + android_key);
|
||||
for (const auto& [key, value] : fs_mgr_parse_boot_config(cmdline)) {
|
||||
for (const auto& [key, value] : fs_mgr_parse_cmdline(cmdline)) {
|
||||
if (key == cmdline_key) {
|
||||
*out_val = value;
|
||||
return true;
|
||||
|
@ -76,6 +114,17 @@ bool fs_mgr_get_boot_config_from_kernel(const std::string& cmdline, const std::s
|
|||
return false;
|
||||
}
|
||||
|
||||
// Tries to get the given boot config value from bootconfig.
|
||||
// Returns true if successfully found, false otherwise.
|
||||
bool fs_mgr_get_boot_config_from_bootconfig_source(const std::string& key, std::string* out_val) {
|
||||
std::string bootconfig;
|
||||
if (!android::base::ReadFileToString("/proc/bootconfig", &bootconfig)) return false;
|
||||
if (!bootconfig.empty() && bootconfig.back() == '\n') {
|
||||
bootconfig.pop_back();
|
||||
}
|
||||
return fs_mgr_get_boot_config_from_bootconfig(bootconfig, key, out_val);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
@ -110,6 +159,11 @@ bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val) {
|
|||
return true;
|
||||
}
|
||||
|
||||
// next, check if we have the property in bootconfig
|
||||
if (fs_mgr_get_boot_config_from_bootconfig_source(key, out_val)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// finally, fallback to kernel cmdline, properties may not be ready yet
|
||||
if (fs_mgr_get_boot_config_from_kernel_cmdline(key, out_val)) {
|
||||
return true;
|
||||
|
|
|
@ -854,7 +854,7 @@ std::set<std::string> GetBootDevices() {
|
|||
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_boot_config(cmdline)) {
|
||||
for (const auto& [key, value] : fs_mgr_parse_cmdline(cmdline)) {
|
||||
if (key == cmdline_key) {
|
||||
boot_devices.emplace(value);
|
||||
}
|
||||
|
|
|
@ -22,11 +22,16 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> fs_mgr_parse_boot_config(const std::string& cmdline);
|
||||
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);
|
||||
std::vector<std::pair<std::string, std::string>> fs_mgr_parse_proc_bootconfig(
|
||||
const std::string& bootconfig);
|
||||
bool fs_mgr_get_boot_config_from_bootconfig(const std::string& bootconfig, const std::string& key,
|
||||
std::string* out_val);
|
||||
bool fs_mgr_get_boot_config_from_bootconfig_source(const std::string& key, std::string* out_val);
|
||||
|
||||
#endif /* __CORE_FS_MGR_PRIV_BOOTCONFIG_H */
|
||||
|
|
|
@ -119,10 +119,73 @@ const std::vector<std::pair<std::string, std::string>> result_space = {
|
|||
{"terminator", "truncated"},
|
||||
};
|
||||
|
||||
const std::string bootconfig =
|
||||
"androidboot.bootdevice = \" \"1d84000.ufshc\"\n"
|
||||
"androidboot.baseband = \"sdy\"\n"
|
||||
"androidboot.keymaster = \"1\"\n"
|
||||
"androidboot.serialno = \"BLAHBLAHBLAH\"\n"
|
||||
"androidboot.slot_suffix = \"_a\"\n"
|
||||
"androidboot.hardware.platform = \"sdw813\"\n"
|
||||
"androidboot.hardware = \"foo\"\n"
|
||||
"androidboot.revision = \"EVT1.0\"\n"
|
||||
"androidboot.bootloader = \"burp-0.1-7521\"\n"
|
||||
"androidboot.hardware.sku = \"mary\"\n"
|
||||
"androidboot.hardware.radio.subtype = \"0\"\n"
|
||||
"androidboot.dtbo_idx = \"2\"\n"
|
||||
"androidboot.mode = \"normal\"\n"
|
||||
"androidboot.hardware.ddr = \"1GB,combuchi,LPDDR4X\"\n"
|
||||
"androidboot.ddr_info = \"combuchiandroidboot.ddr_size=2GB\"\n"
|
||||
"androidboot.hardware.ufs = \"2GB,combushi\"\n"
|
||||
"androidboot.boottime = \"0BLE:58,1BLL:22,1BLE:571,2BLL:105,ODT:0,AVB:123\"\n"
|
||||
"androidboot.ramdump = \"disabled\"\n"
|
||||
"androidboot.vbmeta.device = \"PARTUUID=aa08f1a4-c7c9-402e-9a66-9707cafa9ceb\"\n"
|
||||
"androidboot.vbmeta.avb_version = \"1.1\"\n"
|
||||
"androidboot.vbmeta.device_state = \"unlocked\"\n"
|
||||
"androidboot.vbmeta.hash_alg = \"sha256\"\n"
|
||||
"androidboot.vbmeta.size = \"5248\"\n"
|
||||
"androidboot.vbmeta.digest = \""
|
||||
"ac13147e959861c20f2a6da97d25fe79e60e902c022a371c5c039d31e7c68860\"\n"
|
||||
"androidboot.vbmeta.invalidate_on_error = \"yes\"\n"
|
||||
"androidboot.veritymode = \"enforcing\"\n"
|
||||
"androidboot.verifiedbootstate = \"orange\"\n"
|
||||
"androidboot.space = \"sha256 5248 androidboot.nospace = nope\"\n";
|
||||
|
||||
const std::vector<std::pair<std::string, std::string>> bootconfig_result_space = {
|
||||
{"androidboot.bootdevice", "1d84000.ufshc"},
|
||||
{"androidboot.baseband", "sdy"},
|
||||
{"androidboot.keymaster", "1"},
|
||||
{"androidboot.serialno", "BLAHBLAHBLAH"},
|
||||
{"androidboot.slot_suffix", "_a"},
|
||||
{"androidboot.hardware.platform", "sdw813"},
|
||||
{"androidboot.hardware", "foo"},
|
||||
{"androidboot.revision", "EVT1.0"},
|
||||
{"androidboot.bootloader", "burp-0.1-7521"},
|
||||
{"androidboot.hardware.sku", "mary"},
|
||||
{"androidboot.hardware.radio.subtype", "0"},
|
||||
{"androidboot.dtbo_idx", "2"},
|
||||
{"androidboot.mode", "normal"},
|
||||
{"androidboot.hardware.ddr", "1GB,combuchi,LPDDR4X"},
|
||||
{"androidboot.ddr_info", "combuchiandroidboot.ddr_size=2GB"},
|
||||
{"androidboot.hardware.ufs", "2GB,combushi"},
|
||||
{"androidboot.boottime", "0BLE:58,1BLL:22,1BLE:571,2BLL:105,ODT:0,AVB:123"},
|
||||
{"androidboot.ramdump", "disabled"},
|
||||
{"androidboot.vbmeta.device", "PARTUUID=aa08f1a4-c7c9-402e-9a66-9707cafa9ceb"},
|
||||
{"androidboot.vbmeta.avb_version", "1.1"},
|
||||
{"androidboot.vbmeta.device_state", "unlocked"},
|
||||
{"androidboot.vbmeta.hash_alg", "sha256"},
|
||||
{"androidboot.vbmeta.size", "5248"},
|
||||
{"androidboot.vbmeta.digest",
|
||||
"ac13147e959861c20f2a6da97d25fe79e60e902c022a371c5c039d31e7c68860"},
|
||||
{"androidboot.vbmeta.invalidate_on_error", "yes"},
|
||||
{"androidboot.veritymode", "enforcing"},
|
||||
{"androidboot.verifiedbootstate", "orange"},
|
||||
{"androidboot.space", "sha256 5248 androidboot.nospace = nope"},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(fs_mgr, fs_mgr_parse_boot_config) {
|
||||
EXPECT_EQ(result_space, fs_mgr_parse_boot_config(cmdline));
|
||||
TEST(fs_mgr, fs_mgr_parse_cmdline) {
|
||||
EXPECT_EQ(result_space, fs_mgr_parse_cmdline(cmdline));
|
||||
}
|
||||
|
||||
TEST(fs_mgr, fs_mgr_get_boot_config_from_kernel_cmdline) {
|
||||
|
@ -140,6 +203,27 @@ TEST(fs_mgr, fs_mgr_get_boot_config_from_kernel_cmdline) {
|
|||
EXPECT_TRUE(content.empty()) << content;
|
||||
}
|
||||
|
||||
TEST(fs_mgr, fs_mgr_parse_bootconfig) {
|
||||
EXPECT_EQ(bootconfig_result_space, fs_mgr_parse_proc_bootconfig(bootconfig));
|
||||
}
|
||||
|
||||
TEST(fs_mgr, fs_mgr_get_boot_config_from_bootconfig) {
|
||||
std::string content;
|
||||
for (const auto& entry : bootconfig_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_bootconfig(bootconfig, key, &content))
|
||||
<< " for " << key;
|
||||
EXPECT_EQ(entry.second, content);
|
||||
}
|
||||
|
||||
EXPECT_FALSE(fs_mgr_get_boot_config_from_bootconfig(bootconfig, "vbmeta.avb_versio", &content));
|
||||
EXPECT_TRUE(content.empty()) << content;
|
||||
EXPECT_FALSE(fs_mgr_get_boot_config_from_bootconfig(bootconfig, "nospace", &content));
|
||||
EXPECT_TRUE(content.empty()) << content;
|
||||
}
|
||||
|
||||
TEST(fs_mgr, fs_mgr_read_fstab_file_proc_mounts) {
|
||||
Fstab fstab;
|
||||
ASSERT_TRUE(ReadFstabFromFile("/proc/mounts", &fstab));
|
||||
|
|
|
@ -209,6 +209,8 @@ int FirstStageMain(int argc, char** argv) {
|
|||
CHECKCALL(chmod("/proc/cmdline", 0440));
|
||||
std::string cmdline;
|
||||
android::base::ReadFileToString("/proc/cmdline", &cmdline);
|
||||
// Don't expose the raw bootconfig to unprivileged processes.
|
||||
chmod("/proc/bootconfig", 0440);
|
||||
gid_t groups[] = {AID_READPROC};
|
||||
CHECKCALL(setgroups(arraysize(groups), groups));
|
||||
CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL));
|
||||
|
|
|
@ -1180,6 +1180,14 @@ static void ProcessKernelCmdline() {
|
|||
}
|
||||
}
|
||||
|
||||
static void ProcessBootconfig() {
|
||||
ImportBootconfig([&](const std::string& key, const std::string& value) {
|
||||
if (StartsWith(key, "androidboot.")) {
|
||||
InitPropertySet("ro.boot." + key.substr(12), value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void PropertyInit() {
|
||||
selinux_callback cb;
|
||||
cb.func_audit = PropertyAuditCallback;
|
||||
|
@ -1198,6 +1206,7 @@ void PropertyInit() {
|
|||
// properties set in DT always have priority over the command-line ones.
|
||||
ProcessKernelDt();
|
||||
ProcessKernelCmdline();
|
||||
ProcessBootconfig();
|
||||
|
||||
// Propagate the kernel variables to internal variables
|
||||
// used by init as well as the current required properties.
|
||||
|
|
|
@ -246,6 +246,19 @@ void ImportKernelCmdline(const std::function<void(const std::string&, const std:
|
|||
}
|
||||
}
|
||||
|
||||
void ImportBootconfig(const std::function<void(const std::string&, const std::string&)>& fn) {
|
||||
std::string bootconfig;
|
||||
android::base::ReadFileToString("/proc/bootconfig", &bootconfig);
|
||||
|
||||
for (const auto& entry : android::base::Split(bootconfig, "\n")) {
|
||||
std::vector<std::string> pieces = android::base::Split(entry, "=");
|
||||
if (pieces.size() == 2) {
|
||||
pieces[1].erase(std::remove(pieces[1].begin(), pieces[1].end(), '"'), pieces[1].end());
|
||||
fn(android::base::Trim(pieces[0]), android::base::Trim(pieces[1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool make_dir(const std::string& path, mode_t mode) {
|
||||
std::string secontext;
|
||||
if (SelabelLookupFileContext(path, mode, &secontext) && !secontext.empty()) {
|
||||
|
|
|
@ -55,6 +55,7 @@ Result<uid_t> DecodeUid(const std::string& name);
|
|||
bool mkdir_recursive(const std::string& pathname, mode_t mode);
|
||||
int wait_for_file(const char *filename, std::chrono::nanoseconds timeout);
|
||||
void ImportKernelCmdline(const std::function<void(const std::string&, const std::string&)>&);
|
||||
void ImportBootconfig(const std::function<void(const std::string&, const std::string&)>&);
|
||||
bool make_dir(const std::string& path, mode_t mode);
|
||||
bool is_dir(const char* pathname);
|
||||
Result<std::string> ExpandProps(const std::string& src);
|
||||
|
|
Loading…
Reference in a new issue