Android 11属性系统初始化流程

在init进程启动的第二阶段,调用PropertyInit 对属性系统进行初始化

int SecondStageMain(int argc, char** argv) {//省略PropertyInit();//省略
}

PropertyInit函数在system\core\init\property_service.cpp 中实现

void PropertyInit() {//省略mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH); //1CreateSerializedPropertyInfo();//2if (__system_property_area_init()) {//3LOG(FATAL) << "Failed to initialize property area";}if (!property_info_area.LoadDefaultPath()) {LOG(FATAL) << "Failed to load serialized property info file";}// If arguments are passed both on the command line and in DT,// properties set in DT always have priority over the command-line ones.ProcessKernelDt(); //4ProcessKernelCmdline();//5// Propagate the kernel variables to internal variables// used by init as well as the current required properties.ExportKernelBootProps();//6PropertyLoadBootDefaults();//7
}

注释1处在dev下创建__properties__文件夹。注释2处会收集读取各个分区下的property_contexts文件,将读取到的信息系列化之后,写到/dev/properties/property_info文件中。注释3处会读取/dev/properties/property_info文件构建ContextNode 数组,并在/dev/__properties__目录下,创建属性文件.注释4处处理内核dts中的属性信息。注释5处理cmdline中的属性信息。注释6导出一些属性给另外的属性赋值。注释7加载系统默认的属性文件。

接下来一项一项的来分析

CreateSerializedPropertyInfo

void CreateSerializedPropertyInfo() {auto property_infos = std::vector<PropertyInfoEntry>();if (access("/system/etc/selinux/plat_property_contexts", R_OK) != -1) {if (!LoadPropertyInfoFromFile("/system/etc/selinux/plat_property_contexts",&property_infos)) {return;}// Don't check for failure here, so we always have a sane list of properties.// E.g. In case of recovery, the vendor partition will not have mounted and we// still need the system / platform properties to function.if (access("/system_ext/etc/selinux/system_ext_property_contexts", R_OK) != -1) {LoadPropertyInfoFromFile("/system_ext/etc/selinux/system_ext_property_contexts",&property_infos);}if (!LoadPropertyInfoFromFile("/vendor/etc/selinux/vendor_property_contexts",&property_infos)) {// Fallback to nonplat_* if vendor_* doesn't exist.LoadPropertyInfoFromFile("/vendor/etc/selinux/nonplat_property_contexts",&property_infos);}if (access("/product/etc/selinux/product_property_contexts", R_OK) != -1) {LoadPropertyInfoFromFile("/product/etc/selinux/product_property_contexts",&property_infos);}if (access("/odm/etc/selinux/odm_property_contexts", R_OK) != -1) {LoadPropertyInfoFromFile("/odm/etc/selinux/odm_property_contexts", &property_infos);}} //省略auto serialized_contexts = std::string();auto error = std::string();if (!BuildTrie(property_infos, "u:object_r:default_prop:s0", "string", &serialized_contexts,&error)) {LOG(ERROR) << "Unable to serialize property contexts: " << error;return;}constexpr static const char kPropertyInfosPath[] = "/dev/__properties__/property_info";if (!WriteStringToFile(serialized_contexts, kPropertyInfosPath, 0444, 0, 0, false)) {PLOG(ERROR) << "Unable to write serialized property infos to file";}selinux_android_restorecon(kPropertyInfosPath, 0);
  • 初始化property_infos 动态数组
  • 调用LoadPropertyInfoFromFile分别读取各目录下的property_contexts文件,将读取到的信息构建PropertyInfoEntry并放入property_infos 数组
  • BuildTrie对数组进行系列化(构建字典树并对字典树进行TrieBuilerNode 对象系列化),
  • 将系列化后的信息通过WriteStringToFile写进/dev/properties/property_info文件

__system_property_area_init
__system_property_area_init的实现在bionic\libc\bionic\system_property_api.cpp文件中

//#define PROP_FILENAME "/dev/__properties__"
int __system_property_area_init() {bool fsetxattr_failed = false;return system_properties.AreaInit(PROP_FILENAME, &fsetxattr_failed) && !fsetxattr_failed ? 0 : -1;
}

AreaInit函数实现在bionic\libc\system_properties\system_properties.cpp文件中

bool SystemProperties::AreaInit(const char* filename, bool* fsetxattr_failed) {if (strlen(filename) >= PROP_FILENAME_MAX) {return false;}strcpy(property_filename_, filename);contexts_ = new (contexts_data_) ContextsSerialized();if (!contexts_->Initialize(true, property_filename_, fsetxattr_failed)) {return false;}initialized_ = true;return true;
}

先初始化一个ContextsSerialized对象,然后调用其Initialize函数。注意第一个参数。为true时,则会创建所有的/dev/properties/property_info/u:object_r:*:s0属性安全上下文文件,并在mmap时具有可读写权限。为false时,则不会创建文件且在映射时,只有可读的权限。
接着看一下Initialize函数,实现在bionic\libc\system_properties\contexts_serialized.cpp文件中

bool ContextsSerialized::Initialize(bool writable, const char* filename, bool* fsetxattr_failed) {filename_ = filename;if (!InitializeProperties()) {return false;}if (writable) {mkdir(filename_, S_IRWXU | S_IXGRP | S_IXOTH);bool open_failed = false;if (fsetxattr_failed) {*fsetxattr_failed = false;}for (size_t i = 0; i < num_context_nodes_; ++i) {if (!context_nodes_[i].Open(true, fsetxattr_failed)) {open_failed = true;}}if (open_failed || !MapSerialPropertyArea(true, fsetxattr_failed)) { //映射具有读写权限FreeAndUnmap();return false;}} else {if (!MapSerialPropertyArea(false, nullptr)) { //映射只有读的权限FreeAndUnmap();return false;}}return true;
}

在InitializeProperties函数中,会加载/dev/properties/property_info文件,并映射一块内存,然后通过一个 for 循环,将这块内存初始化为一个 ContextNode 的数组结构,每个 ContextNode 对象中的信息保存了一个安全上下文信息和文件路径信息。
完成上面的工作之后,通过for循环,调用每个ContextNode 的Open函数,在Open函数中,会根据属性安全上下文创建属性文件,如dev/properties/u:object_r:hwservicemanager_prop:s0,并映射它,将映射的地址保存在ContextNode 中。需要说明的是,相同安全上下文的不同属性,都会存放在同一片共享内存中,内存的名字就是其安全上下文(比如属性的安全上下文名字为adbd_config_prop,则存放在dev/properties/u:object_r:adbd_config_prop:s0文件中)。

ls -lh dev/__properties__/
-r--r--r-- 1 root root 128K 2017-01-01 20:00 u:object_r:adbd_config_prop:s0
-r--r--r-- 1 root root 128K 2017-01-01 20:00 u:object_r:adbd_prop:s0
-r--r--r-- 1 root root 128K 2017-01-01 20:00 u:object_r:apexd_prop:s0
-r--r--r-- 1 root root 128K 2017-01-01 20:00 u:object_r:apk_verity_prop:s0
-r--r--r-- 1 root root 128K 2017-01-01 20:00 u:object_r:audio_prop:s0

ProcessKernelDt

static void ProcessKernelDt() {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(), ',', '.');InitPropertySet("ro.boot."s + dp->d_name, dt_file);}
}

首先检查compatible属性的值是"android,firmware"如果不是,函数直接返回。如果是的话,再打开目录下的dts文件,并读取其内容。其中 get_android_dt_dir是在cmdline中指定

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 cmdlineImportKernelCmdline([&](const std::string& key, const std::string& value) {if (key == "androidboot.android_dt_dir") {android_dt_dir = value;}});LOG(INFO) << "Using Android DT directory " << android_dt_dir;return 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;
}

比如androidboot.android_dt_dir目录下有cpu.dts和dispaly.dts,满足条件的话,则会将两个文件的内容分别设置ro.boot.cpu和ro.boot.dispaly

ProcessKernelCmdline

static void ProcessKernelCmdline() {bool for_emulator = false;ImportKernelCmdline([&](const std::string& key, const std::string& value) {if (key == "qemu") {for_emulator = true;} else if (StartsWith(key, "androidboot.")) {InitPropertySet("ro.boot." + key.substr(12), value);}});if (for_emulator) {ImportKernelCmdline([&](const std::string& key, const std::string& value) {// In the emulator, export any kernel option with the "ro.kernel." prefix.InitPropertySet("ro.kernel." + key, value);});}
}

解析cmdline中的数据设置其属性。如:androidboot.mode=normal 会转化成:ro.boot.mode=normal

ExportKernelBootProps

static void ExportKernelBootProps() {constexpr const char* UNSET = "";struct {const char* src_prop;const char* dst_prop;const char* default_value;} prop_map[] = {// clang-format off{ "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", },// clang-format on};for (const auto& prop : prop_map) {std::string value = GetProperty(prop.src_prop, prop.default_value);if (value != UNSET) InitPropertySet(prop.dst_prop, value);}
}

如果系统中有ro.boot.serialno这个属性,则将其值也设置给ro.serialno
PropertyLoadBootDefaults

加载系统默认的属性文件。参考初识Android 属性

总结

在初始化属性系统时,会加载各个分区的property_contexts文件,并进行TrieBuilerNode 对象系列化,然后将系列化的信息写入到dev/properties/propert_info文件中。根据该文件信息(name,安全上下文),在dev/properties/目录下创建内存文件,并进行映射,地址保存在ContextNode 中。创建的内存文件的名字是属性的安全上下文。ContextNode 和TrieBuilerNode 是一一对应的。内存创建好之后,还会根据dts,cmdline中的信息,生成属性。最后加载各个分区默认的属性文件。

以下为简略的逻辑图,每个内存文件为128k
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/799294.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

智能网联汽车自动驾驶数据记录系统DSSAD数据元素

目录 第一章 数据元素分级 第二章 数据元素分类 第三章 数据元素基本信息表 表1 车辆及自动驾驶数据记录系统基本信息 表2 车辆状态及动态信息 表3 自动驾驶系统运行信息 表4 行车环境信息 表5 驾驶员操作及状态信息 第一章 数据元素分级 自动驾驶数据记录系统记录的数…

【GameFi】 链游 | Brilliantcrypto点火活动

活动&#xff1a;https://app.galxe.com/quest/brilliantcrypto/GCt8wthq2J Brilliantcrypto点火活动正在Galxe上进行 &#x1f389; 活动时间&#xff1a;2024/04/06 12:00 ~ 2024/05/04 12:00 奖励总价值1200美元的MATIC 完成任务並在Brilliantcrypto Galxe Space上赚取积分。…

【数据结构与算法】:快速排序和冒泡排序

一&#xff0c;快速排序 快速排序是一种比较复杂的排序算法&#xff0c;它总共有4种实现方式&#xff0c;分别是挖坑法&#xff0c;左右"指针"法&#xff0c;前后"指针"法&#xff0c;以及非递归的快速排序&#xff0c;并且这些算法中也会涉及多种优化措施…

zdpdjango_materialadmin使用Django开发一个Material风格的后台管理系统

启动项目 同样地&#xff0c;还是先看看代码&#xff1a; 将项目启动起来&#xff1a; 浏览器访问&#xff1a;http://localhost:8000/ 代码初步优化 首先是将admin_materal提到本地来&#xff1a; 移除掉第三方依赖&#xff1a; pip uninstall django-admin-materi…

移动平台相关(安卓)

目录 安卓开发 Unity打包安卓 ​编辑​编辑 BuildSettings PlayerSettings OtherSettings 身份证明 配置 脚本编译 优化 PublishingSettings 调试 ReMote Android Logcat AndroidStudio的调试 Java语法 ​编辑​编辑​编辑 变量 运算符 ​编辑​编辑​编辑​…

面向低碳经济运行目标的多微网能量互联优化调度matlab程序

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 运用平台 matlabgurobi 程序简介 该程序为多微网协同优化调度模型&#xff0c;系统在保障综合效益的基础上&#xff0c;调度时优先协调微网与微网之间的能量流动&#xff0c;将与大电网的互联交互作为备用…

百度松果菁英班——机器学习实践四:文本词频分析

飞桨AI Studio星河社区-人工智能学习与实训社区 &#x1f96a;jieba分词词频统计 import jieba # jieba中文分词库 ​ with open(test.txt, r, encodingUTF-8) as novelFile:novel novelFile.read() # print(novel) stopwords [line.strip() for line in open(stop.txt, r,…

初识C++ · 类和对象(上)

目录 1.面向过程和面向对象初步认识 2.类的引入 3.类的定义 4.类的访问限定符及封装 4.1 访问限定符 4.2 封装 5.类的作用域 6.类的实例化 7.类的对象大小的计算 8.类成员函数的this指针 1.面向过程和面向对象初步认识 C语言是一门面向过程的语言&#xff0c;注重的…

vue+springboot多角色登录

①前端编写 将Homeview修改为manager Manager&#xff1a; <template><div><el-container><!-- 侧边栏 --><el-aside :width"asideWidth" style"min-height: 100vh; background-color: #001529"><div style"h…

百度文库验证码识别

一、前言 百度出了如图所示的验证码&#xff0c;需要拖动滑块&#xff0c;与如图所示的曲线轨迹进行重合。经过不断研究&#xff0c;终于解决了这个问题。我把识别代码分享给大家。 下面是使用selenium进行验证的&#xff0c;这样可以看到轨迹滑动的过程&#xff0c;如果需要…

亚马逊店铺引流:海外云手机的利用方法

在电商业务蓬勃发展的当下&#xff0c;亚马逊已经成为全球最大的电商平台之一&#xff0c;拥有庞大的用户群和交易量。在激烈的市场竞争中&#xff0c;如何有效地吸引流量成为亚马逊店铺经营者所关注的重点。海外云手机作为一项新兴技术工具&#xff0c;为亚马逊店铺的流量引导…

页面转word的那些事

背景 有些时候需要将页面内容或者是页面的数据通过word进行下载&#xff0c;以方便客户进行二次编辑&#xff0c;而不是直接导出图片或者是pdf。 想在页面端点击下载成word&#xff0c;那必然需要服务端来进行读写文件&#xff0c;无论是你后端编辑好的内容流&#xff0c;还是…

从头开发一个RISC-V的操作系统(五)汇编语言编程

文章目录 前提RISC-V汇编语言入门RISC-V汇编指令总览汇编指令操作对象汇编指令编码格式add指令介绍无符号数 练习参考链接 目标&#xff1a;通过这一个系列课程的学习&#xff0c;开发出一个简易的在RISC-V指令集架构上运行的操作系统。 前提 这个系列的大部分文章和知识来自于…

VMware Intel i5-10400 安装Mac 14 Sonoma

目录 安装完后的效果安装前的准备创建虚拟机创建虚拟机&#xff0c;选择典型安装。选择ISO文件选择系统类型命名虚拟机设置磁盘完成 配置虚拟机文件修改配置文件 第一次运行虚拟机选择语言选择磁盘工具格式磁盘安装macOS Sonoma 其他问题登录Apple帐户 &#xff1a; MOBILEME_C…

单点登录系统设计

一、介绍 token鉴权最佳的实践场景就是在单点登录系统上。 在企业发展初期&#xff0c;使用的后台管理系统还比较少&#xff0c;一个或者两个。 以电商系统为例&#xff0c;在起步阶段&#xff0c;可能只有一个商城下单系统和一个后端管理产品和库存的系统。 随着业务量越来…

药店药品进销存管理系统软件可以对有效期管理查询以及对批号库存管理

药店药品进销存管理系统软件可以对有效期管理查询以及对批号库存管理 一、前言 以下软件操作教程以&#xff0c;佳易王药店药品进销存管理软件为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 软件可以对药品有效期进行管理查询&#xff0c;可以…

【C++进阶】哈希表(哈希函数、哈希冲突、开散列、闭散列)

&#x1fa90;&#x1fa90;&#x1fa90;欢迎来到程序员餐厅&#x1f4ab;&#x1f4ab;&#x1f4ab; 主厨&#xff1a;邪王真眼 主厨的主页&#xff1a;Chef‘s blog 所属专栏&#xff1a;c大冒险 总有光环在陨落&#xff0c;总有新星在闪烁 引言&#xff1a; 我们之前…

【Frida】【Android】 10_爬虫之WebSocket协议分析

&#x1f6eb; 系列文章导航 【Frida】【Android】01_手把手教你环境搭建 https://blog.csdn.net/kinghzking/article/details/136986950【Frida】【Android】02_JAVA层HOOK https://blog.csdn.net/kinghzking/article/details/137008446【Frida】【Android】03_RPC https://bl…

实现第一个动态链接库 游戏插件 成功在主程序中运行 dll 中定义的类

devc 5.11编译环境 dll编译环境设置参考 Dev c C语言实现第一个 dll 动态链接库 创建与调用-CSDN博客 插件 DLL代码和主程序代码如下 注意 dll 代码中的class 类名需要 和主程序 相同 其中使用了函数指针和强制类型转换 函数指针教程参考 以动态库链接库 .dll 探索结构体…

HBase详解(2)

HBase 结构 HRegion 概述 在HBase中&#xff0c;会从行键方向上对表来进行切分&#xff0c;切分出来的每一个结构称之为是一个HRegion 切分之后&#xff0c;每一个HRegion会交给某一个HRegionServer来进行管理。HRegionServer是HBase的从节点&#xff0c;每一个HRegionServ…