当前位置: 首页 > web >正文

安卓系统属性之androidboot.xxx转换成ro.boot.xxx

目录

  • 前言
  • 一、init进程-->SecondStageMain
  • 二、process_kernel_dt
    • 2.1 is_android_dt_value_expected
      • 2.1.1 read_android_dt_file
      • 2.1.2 get_android_dt_dir
      • 2.1.3 init_android_dt_dir
      • 2.1.4 import_kernel_cmdline
    • 2.2 property_set()设置属性
  • 三、process_kernel_cmdline
    • 3.1 import_kernel_cmdline(false, import_kernel_nv);
    • 3.2 import_kernel_cmdline(true, import_kernel_nv);
  • 四、export_kernel_boot_props
  • 五、总结


前言

kermel cmdline中我们经常会设置androidboot.xxx比如androidboot.selinux=disabled

但是代码中并不能搜到对应的内容,其实是init进程做了统一转换。

一、init进程–>SecondStageMain

init进程的SecondStageMain阶段,执行了process_kernel_dtprocess_kernel_cmdline

system\core\init\main.cpp
int main(int argc, char** argv) {
......if (!strcmp(argv[1], "second_stage")) {return SecondStageMain(argc, argv);}}
......return FirstStageMain(argc, argv);
}
int SecondStageMain(int argc, char** argv) {
......property_init();// If arguments are passed both on the command line and in DT,// properties set in DT always have priority over the command-line ones.process_kernel_dt();process_kernel_cmdline();// Propagate the kernel variables to internal variables// used by init as well as the current required properties.export_kernel_boot_props();......

翻译一下:

如果参数既在命令行中传递,又在DT中传递,则DT中设置的属性始终优先于命令行中的属性。
将内核命令行传播到由init进程使用的内部变量以及当前所需的属性中。


二、process_kernel_dt

static void process_kernel_dt() {if (!is_android_dt_value_expected("compatible", "android,firmware")) {return;}std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(get_android_dt_dir().c_str()), closedir);if (!dir) return;std::string dt_file;struct dirent *dp;while ((dp = readdir(dir.get())) != NULL) {if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible") || !strcmp(dp->d_name, "name")) {continue;}std::string file_name = get_android_dt_dir() + dp->d_name;android::base::ReadFileToString(file_name, &dt_file);std::replace(dt_file.begin(), dt_file.end(), ',', '.');property_set("ro.boot."s + dp->d_name, dt_file);}
}

2.1 is_android_dt_value_expected

if (!is_android_dt_value_expected("compatible", "android,firmware")) {return;
}

从方法的名字上也可以推测出来,检查设备树(Device Tree)中的某个属性(这里是 “compatible”)的值是否符合预期(这里是 “android,firmware”)。如果不是,直接return。

bool is_android_dt_value_expected(const std::string& sub_path, const std::string& expected_content) {std::string dt_content;if (read_android_dt_file(sub_path, &dt_content)) {if (dt_content == expected_content) {return true;}}return false;
}

“从设备树的compatible路径读取内容,并判断内容是否与android,firmware完全相等。”
如果相等,返回true;否则返回false

2.1.1 read_android_dt_file

// Reads the content of device tree file under the platform's Android DT directory.
// Returns true if the read is success, false otherwise.
bool read_android_dt_file(const std::string& sub_path, std::string* dt_content) {const std::string file_name = get_android_dt_dir() + sub_path;if (android::base::ReadFileToString(file_name, dt_content)) {if (!dt_content->empty()) {dt_content->pop_back();  // Trims the trailing '\0' out.return true;}}return false;
}

先来翻译一下:

读取平台Android DT目录下的设备树文件内容。如果读取成功,则返回true,否则返回false

  • 1.构建完整文件路径file_name;
  • 2.调用ReadFileToString()读取文件;
  • 3.如果读取成功,且内容不为空:
    删除内容末尾的\0字符;
    返回true;
    否则,返回false。

2.1.2 get_android_dt_dir

// FIXME: The same logic is duplicated in system/core/fs_mgr/
const std::string& get_android_dt_dir() {// Set once and saves time for subsequent calls to this functionstatic const std::string kAndroidDtDir = init_android_dt_dir();return kAndroidDtDir;
}

直接调用init_android_dt_dir初始化设备树目录,然后返回这个目录

2.1.3 init_android_dt_dir

const std::string kDefaultAndroidDtDir("/proc/device-tree/firmware/android/");static std::string init_android_dt_dir() {// Use the standard procfs-based path by defaultstd::string android_dt_dir = kDefaultAndroidDtDir;// The platform may specify a custom Android DT path in kernel cmdlineimport_kernel_cmdline(false,[&](const std::string& key, const std::string& value, bool in_qemu) {if (key == "androidboot.android_dt_dir") {android_dt_dir = value;}});LOG(INFO) << "Using Android DT directory " << android_dt_dir;return android_dt_dir;
}
  • 初始化Android设备树(Device Tree)目录路径
  • 默认路径为:/proc/device-tree/firmware/android/
  • 如果内核启动参数(cmdline)中指定了androidboot.android_dt_dir,则会覆盖默认路径,
    这里使用了lambda表达式

2.1.4 import_kernel_cmdline

void import_kernel_cmdline(bool in_qemu,const std::function<void(const std::string&, const std::string&, bool)>& fn) {std::string cmdline;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) {fn(pieces[0], pieces[1], in_qemu);}}
}
  • /proc/cmdline读取内核启动参数字符串。
  • 解析出所有参数(空格分隔的字符串,例如:param1=val1 param2=val2 …)。
  • 对每个参数,调用提供的回调函数fn,传入参数名、值和标志位in_qemu

看一下我本地的路径以及其对应的值

Android:/proc/device-tree/firmware/android # ls
compatible hardware mode name serialnoAndroid:/proc/device-tree/firmware/android # cat compatible
android,firmware

2.2 property_set()设置属性

static void process_kernel_dt() {if (!is_android_dt_value_expected("compatible", "android,firmware")) {return;}std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(get_android_dt_dir().c_str()), closedir);if (!dir) return;std::string dt_file;struct dirent *dp;while ((dp = readdir(dir.get())) != NULL) {if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible") || !strcmp(dp->d_name, "name")) {continue;}std::string file_name = get_android_dt_dir() + dp->d_name;android::base::ReadFileToString(file_name, &dt_file);std::replace(dt_file.begin(), dt_file.end(), ',', '.');property_set("ro.boot."s + dp->d_name, dt_file);}
}

然后这个目录下以每个文件名作为属性(除了compatible 和name),文件里面的内容作为属性值。这里的话就是ro.boot.harewarero.boot.modero.boot.serialno这三个属性值

Android:/proc/device-tree/firmware/android # ls
compatible hardware mode name serialno
Android:/proc/device-tree/firmware/android #

三、process_kernel_cmdline

static char qemu[32];static void process_kernel_cmdline() {// The first pass does the common stuff, and finds if we are in qemu.// The second pass is only necessary for qemu to export all kernel params// as properties.import_kernel_cmdline(false, import_kernel_nv);if (qemu[0]) import_kernel_cmdline(true, import_kernel_nv);
}void import_kernel_cmdline(bool in_qemu,const std::function<void(const std::string&, const std::string&, bool)>& fn) {std::string cmdline;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) {fn(pieces[0], pieces[1], in_qemu);}}
}static void import_kernel_nv(char *name, bool for_emulator)
{char *value = strchr(name, '=');int name_len = strlen(name);if (value == 0) return;*value++ = 0;if (name_len == 0) return;if (for_emulator) {/* in the emulator, export any kernel option with the* ro.kernel. prefix */char buff[PROP_NAME_MAX];int len = snprintf( buff, sizeof(buff), "ro.kernel.%s", name );if (len < (int)sizeof(buff))property_set( buff, value );return;}if (!strcmp(name,"qemu")) {strlcpy(qemu, value, sizeof(qemu));} else if (!strncmp(name, "androidboot.", 12) && name_len > 12) {const char *boot_prop_name = name + 12;char prop[PROP_NAME_MAX];int cnt;cnt = snprintf(prop, sizeof(prop), "ro.boot.%s", boot_prop_name);if (cnt < PROP_NAME_MAX)property_set(prop, value);}
}
  • 调用import_kernel_cmdline函数,上面已经讲过,就是读取proc/cmdline中的内容。这个函数有两个参数,第一个采纳数标识当前Android是否是模拟器。第二个参数是一个函数指针;主要指的是通过调用import_kernel_nv函数来设置系统属性。

3.1 import_kernel_cmdline(false, import_kernel_nv);

import_kernel_cmdline 第一次执行时,传入import_kernel_nv的形参为for_emulator为0,
因此将匹配name是否为qemu。

  • 如果是,将其值保存在qemu全局静态缓冲区中。
    对于android模拟器,存在/proc/cmdline中存在"qemu=1"字段
    如果for_emulator为1,则将生成 ro.kernel.{name}={value} 属性写入Android属性系统中。
  • 如果不是,则将/proc/cmdline中以androidboot.为开头的键值对,以ro.boot替换,添加到系统属性中。

此时回到process_kernel_cmdline函数,继续执行

3.2 import_kernel_cmdline(true, import_kernel_nv);

当系统为模拟器时,qemu[0]其值为"1",第二次执行import_kernel_cmdline函数,将再次调用import_kernel_nv函数,生成ro.kernel.xxx属性。


四、export_kernel_boot_props

static void export_kernel_boot_props() {constexpr const char* UNSET = "";struct {const char *src_prop;const char *dst_prop;const char *default_value;} prop_map[] = {{ "ro.boot.serialno",   "ro.serialno",   UNSET, },{ "ro.boot.mode",       "ro.bootmode",   "unknown", },{ "ro.boot.baseband",   "ro.baseband",   "unknown", },{ "ro.boot.bootloader", "ro.bootloader", "unknown", },{ "ro.boot.hardware",   "ro.hardware",   "unknown", },{ "ro.boot.revision",   "ro.revision",   "0", },};for (const auto& prop : prop_map) {std::string value = GetProperty(prop.src_prop, prop.default_value);if (value != UNSET)property_set(prop.dst_prop, value);}
}
  • 定义一份“映射表”prop_map,列出需要读取和设置的属性
  • 循环处理每个映射:
    从源属性获取值(如果未定义则使用默认值)
    如果这个值不是空(UNSET空定义),就设置到目标属性。

其实就是将已有的ro.boot.xxx属性键值对设置到了ro.xxx属性键值对中。


五、总结

  1. process_kernel_dt()
    作用
    判断设备树中的compatible属性是否为"android,firmware",确保硬件符合预期。
    遍历设备树目录中的文件(排除特殊文件如compatiblename)。
    读取每个文件的内容,将其中的逗号,替换为点.,并设置为系统属性(ro.boot.*)。
    主要目的
    从设备树采集硬件描述信息(比如硬件版本、型号等),以供之后系统使用。

  2. process_kernel_cmdline()
    作用
    读取内核启动参数(存放在/proc/cmdline)。
    解析参数,将符合特定条件的键值对(比如androidboot.android_dt_dir)传递给回调(如init_android_dt_dir()),用于动态配置系统参数(比如设备树路径)。
    主要目的
    根据内核参数,动态调整系统配置(如设备树路径、硬件信息等)。

  3. export_kernel_boot_props()
    作用
    从系统属性(如ro.boot.serialno等)读取硬件和启动参数信息。
    将这些信息导出到常规属性(如ro.serialno、ro.bootmode),方便系统和应用访问。
    主要目的
    将硬件和启动信息显式存入标准化的系统属性,保证系统和应用可以一致地访问硬件配置信息。

http://www.xdnf.cn/news/17330.html

相关文章:

  • PostgreSQL 强制索引:当重复数据让优化器“失明”时的解决方案
  • 对话访谈|盘古信息×冠捷科技:全球制造标杆的智能化密码
  • 2025 年华数杯全国大学生数学建模竞赛C 题 可调控生物节律的 LED 光源研究--完整成品、思路、模型、代码、结果分享
  • 本地组策略编辑器无法打开(gpedit.msc命令异常)
  • Windows中安装rustup-init.exe以及cargo build报错443
  • Mac 电脑安装 ADB 环境完整指南
  • 【自动驾驶】《Sparse4Dv3》代码学习笔记
  • golang的面向对象编程,struct的使用
  • DLedger(自动选举)
  • 【多重BFS】Monsters
  • 人工智能——自动微分
  • Spring Boot + ONNXRuntime CPU推理加速终极优化
  • 02电气设计-安全继电器电路设计(让电路等级达到P4的安全等级)
  • PostgreSQL面试题及详细答案120道(61-80)
  • 仁懋电子MOT11N45——音响电路的卓越选择
  • 亚马逊广告运营:有什么好用的辅助工具
  • 接口自动化-pytest
  • 如何实现冷库的远程监控?冷库远程监控物联网解决方案
  • Flink-1.19.0-核心源码详解
  • 汽车娱乐信息系统域控制器的网络安全开发方案
  • Redis为什么要引入多线程?
  • 齐护机器人小智AI_MCP图形化编程控制Arduino_ESP32
  • 2025 年最佳no-code和open-source AI Agents
  • GitCode 7月:小程序积分商城更名成长中心、「探索智能仓颉!Cangjie Magic 体验有奖征文活动」圆满收官、深度对话栏目持续热播
  • 数据结构:双向链表(Doubly Linked List)
  • 谷歌DeepMind发布的全新世界模型“Genie 3”
  • 远程连接----ubuntu ,rocky 等Linux系统,WindTerm_2.7.0
  • vue3 el-select el-option 使用
  • 每日算法刷题Day57:8.6:leetcode 单调栈6道题,用时2h
  • 算法训练营DAY55 第十一章:图论part05