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

安卓系统属性之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.dtcms.com/a/319115.html

相关文章:

  • 分布式面经
  • 虚幻GAS底层原理解剖七 (ASC)
  • Day 6: CNN卷积神经网络 - 计算机视觉的核心引擎
  • 多场景两阶段分布式鲁棒优化模型、数据驱动的综合能源系统
  • PostgreSQL面试题及详细答案120道(61-80)
  • 59.螺旋矩阵II
  • 恒虚警检测(CFAR)仿真:杂波边缘与多目标场景分析
  • 目标检测数据集 - 疟疾检测数据集下载「包含VOC、COCO、YOLO三种格式」
  • 微算法科技(NASDAQ:MLGO)利用集成学习方法,实现更低成本、更稳健的区块链虚拟货币交易价格预测
  • RocketMQ概览
  • Kotlin中String的==相等比较符
  • STM32HAL 快速入门(一):点灯前的准备 —— 从软件安装到硬件原理
  • 利用微软SQL Server数据库管理员(SA)口令为空的攻击活动猖獗
  • 思途spring学习0807
  • Java -- Arrays类-- System类-- BigInteger和BigDecimal类
  • 串口通信02 温度传感DS18B20 01 day49
  • jetson上使用opencv的gstreamer进行MIPI和USB摄像头的连接以及udp推流
  • JAVA,Maven分模块设计
  • 语言模型(LM):n-gram模型原理与困惑度(Perplexity)计算详解
  • B-树与B+树
  • AI大模型专题:LLM大模型(初识)
  • dubbo的metadata-report是做啥的
  • 17.11 单卡24G显存微调GLM-4实战:QLoRA到全参数调优,准确率狂飙42.7%
  • Qt: WA_DontCreateNativeAncestors
  • 【缩点 拓扑序】P3119 [USACO15JAN] Grass Cownoisseur G|省选-
  • 【关于Java中==和equals( )和hashCode( )三者异同】
  • 写Rust GPU内核驱动:GPU驱动工作原理简述
  • 【性能测试】---测试工具篇
  • 医疗人效管理新标杆:盖雅工场如何赋能健康服务企业提质增效
  • 「iOS」————自动释放池底层原理