SystemProperties属性加载
android12-release
1、Property属性加载
1.1 初始化属性域
- 创建
/dev/__properties__
- CreateSerializedPropertyInfo()
property contexts:用于声明属性的安全上下文,plat前缀的文件用于声明system属性,nonplat前缀的文件用于
声明vendor属性。
/system/etc/selinux/plat_property_contexts
/system_ext/etc/selinux/system_ext_property_contexts
/vendor/etc/selinux/vendor_property_contexts
/vendor/etc/selinux/nonplat_property_contexts
/product/etc/selinux/product_property_contexts
/odm/etc/selinux/odm_property_contexts
__system_property_area_init()
初始化属性系统区域,清除缓存映射,新建property_filename目录,这个目录的值为/dev/__properties__
bionic/libc/include/sys/_system_properties.h
bionic/libc/bionic/system_property_api.cpp
bionic/libc/system_properties/system_properties.cppproperty_info_area.LoadDefaultPath()
把文件加载内存
system/core/property_service/libpropertyinfoparser/property_info_parser.cpp
1.2 读取读取DT设备树的属性信息
ProcessKernelDt()
- 判断 /proc/device-tree/firmware/android/compatible 文件中的值是否为 android,firmware
- 获取get_android_dt_dir()的值为/proc/device-tree/firmware/android,遍历目录中的文件
InitPropertySet("ro.boot."s + dp->d_name, dt_file)
将ro.boot.文件名
作为key,文件内容作为value
1.3 将kernel cmdline中的“androidboot.”转化为"ro.boot."
ProcessKernelCmdline()
1.4 将kernel bootconfig中的“androidboot.”转化为"ro.boot."
ProcessBootconfig()
1.5 将内核变量传播到 init 使用的内部变量
1.6 加载prop配置文件属性
PropertyLoadBootDefaults()
相关prop目录
/system/build.prop
- /system_ext/etc/build.prop
/system_ext/default.prop
/system_ext/build.prop /vendor/default.prop
/vendor/build.prop
/vendor_dlkm/etc/build.prop
/odm_dlkm/etc/build.prop
- /odm/etc/build.prop
/odm/default.prop
/odm/build.prop - /product/etc/build.prop
/product/default.prop
/product/build.prop
特殊属性处理
- property_initialize_ro_product_props() :ro.product.[brand|device|manufacturer|model|name]
- property_initialize_build_id() :ro.build.id
- property_derive_build_fingerprint() :ro.build.fingerprint
- property_derive_legacy_build_fingerprint() :ro.build.legacy.fingerprint
- property_initialize_ro_cpu_abilist() :ro.product.cpu.[abilist|abilist32|abilist64]
- update_sys_usb_config() :persist.sys.usb.config
void PropertyLoadBootDefaults() {
// We read the properties and their values into a map, in order to always allow properties
// loaded in the later property files to override the properties in loaded in the earlier
// property files, regardless of if they are "ro." properties or not.
std::map<std::string, std::string> properties;
if (IsRecoveryMode()) {
load_properties_from_file("/prop.default", nullptr, &properties);
}
// /<part>/etc/build.prop is the canonical location of the build-time properties since S.
// Falling back to /<part>/defalt.prop and /<part>/build.prop only when legacy path has to
// be supported, which is controlled by the support_legacy_path_until argument.
const auto load_properties_from_partition = [&properties](const std::string& partition,
int support_legacy_path_until) {
auto path = "/" + partition + "/etc/build.prop";
if (load_properties_from_file(path.c_str(), nullptr, &properties)) {
return;
}
// To read ro.<partition>.build.version.sdk, temporarily load the legacy paths into a
// separate map. Then by comparing its value with legacy_version, we know that if the
// partition is old enough so that we need to respect the legacy paths.
std::map<std::string, std::string> temp;
auto legacy_path1 = "/" + partition + "/default.prop";
auto legacy_path2 = "/" + partition + "/build.prop";
load_properties_from_file(legacy_path1.c_str(), nullptr, &temp);
load_properties_from_file(legacy_path2.c_str(), nullptr, &temp);
bool support_legacy_path = false;
auto version_prop_name = "ro." + partition + ".build.version.sdk";
auto it = temp.find(version_prop_name);
if (it == temp.end()) {
// This is embarassing. Without the prop, we can't determine how old the partition is.
// Let's be conservative by assuming it is very very old.
support_legacy_path = true;
} else if (int value;
ParseInt(it->second.c_str(), &value) && value <= support_legacy_path_until) {
support_legacy_path = true;
}
if (support_legacy_path) {
// We don't update temp into properties directly as it might skip any (future) logic
// for resolving duplicates implemented in load_properties_from_file. Instead, read
// the files again into the properties map.
load_properties_from_file(legacy_path1.c_str(), nullptr, &properties);
load_properties_from_file(legacy_path2.c_str(), nullptr, &properties);
} else {
LOG(FATAL) << legacy_path1 << " and " << legacy_path2 << " were not loaded "
<< "because " << version_prop_name << "(" << it->second << ") is newer "
<< "than " << support_legacy_path_until;
}
};
// Order matters here. The more the partition is specific to a product, the higher its
// precedence is.
LoadPropertiesFromSecondStageRes(&properties);
load_properties_from_file("/system/build.prop", nullptr, &properties);
load_properties_from_partition("system_ext", /* support_legacy_path_until */ 30);
// TODO(b/117892318): uncomment the following condition when vendor.imgs for aosp_* targets are
// all updated.
// if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_R__) {
load_properties_from_file("/vendor/default.prop", nullptr, &properties);
// }
load_properties_from_file("/vendor/build.prop", nullptr, &properties);
load_properties_from_file("/vendor_dlkm/etc/build.prop", nullptr, &properties);
load_properties_from_file("/odm_dlkm/etc/build.prop", nullptr, &properties);
load_properties_from_partition("odm", /* support_legacy_path_until */ 28);
load_properties_from_partition("product", /* support_legacy_path_until */ 30);
if (access(kDebugRamdiskProp, R_OK) == 0) {
LOG(INFO) << "Loading " << kDebugRamdiskProp;
load_properties_from_file(kDebugRamdiskProp, nullptr, &properties);
}
for (const auto& [name, value] : properties) {
std::string error;
if (PropertySet(name, value, &error) != PROP_SUCCESS) {
LOG(ERROR) << "Could not set '" << name << "' to '" << value
<< "' while loading .prop files" << error;
}
}
property_initialize_ro_product_props();
property_initialize_build_id();
property_derive_build_fingerprint();
property_derive_legacy_build_fingerprint();
property_initialize_ro_cpu_abilist();
update_sys_usb_config();
}
2、属性设置
2.1 加载时设置
bionic/libc/bionic/system_property_api.cpp
bionic/libc/system_properties/system_properties.cpp
system/core/init/property_service.cpp
IsLegalPropertyName
检查属性key规范
IsLegalPropertyValue()
检查属性value规范
ro.*
属性实际上是“一次写入”,已设置只读属性- 查找属性
__system_property_find()
;存在检查ro.
开头属性,或更新属性__system_property_update()
;不存在则添加__system_property_add()
- 在我们读取所有默认属性之前,不要将
persist.
开头属性写入磁盘,以防止它们被默认值覆盖。 PropertyChanged(name, value)
通知init进程属性值改变
如果 init 尚未启动其主循环,那么它无论如何都不会处理属性更改的消息
static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {
size_t valuelen = value.size();
if (!IsLegalPropertyName(name)) {
*error = "Illegal property name";
return PROP_ERROR_INVALID_NAME;
}
if (auto result = IsLegalPropertyValue(name, value); !result.ok()) {
*error = result.error().message();
return PROP_ERROR_INVALID_VALUE;
}
prop_info* pi = (prop_info*) __system_property_find(name.c_str());
if (pi != nullptr) {
// ro.* properties are actually "write-once".
if (StartsWith(name, "ro.")) {
*error = "Read-only property was already set";
return PROP_ERROR_READ_ONLY_PROPERTY;
}
__system_property_update(pi, value.c_str(), valuelen);
} else {
int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
if (rc < 0) {
*error = "__system_property_add failed";
return PROP_ERROR_SET_FAILED;
}
}
// Don't write properties to disk until after we have read all default
// properties to prevent them from being overwritten by default values.
if (persistent_properties_loaded && StartsWith(name, "persist.")) {
WritePersistentProperty(name, value);
}
// If init hasn't started its main loop, then it won't be handling property changed messages
// anyway, so there's no need to try to send them.
auto lock = std::lock_guard{accept_messages_lock};
if (accept_messages) {
PropertyChanged(name, value);
}
return PROP_SUCCESS;
}
2.2 主动设置
system/core/init/init.cpp
system/libbase/properties.cpp
bionic/libc/bionic/system_property_set.cpp
- 调用
SetProperty("ro.boot.avb_version", avb_version);
bool SetProperty(const std::string& key, const std::string& value) {
return (__system_property_set(key.c_str(), value.c_str()) == 0);
}
__system_property_set()
最终调用writev
进行socket通信
2.3 java层设置
frameworks/base/core/java/android/os/SystemProperties.java
frameworks/base/core/jni/android_os_SystemProperties.cpp
bionic/libc/bionic/system_property_set.cpp
- 通过JNI最终调用
__system_property_set()