SystemProperties属性加载

文章详细阐述了Android12-release中系统属性的加载过程,包括初始化属性域、读取设备树信息、处理内核命令行和配置文件属性,以及属性的设置方法,如加载时设置、主动设置和Java层设置。同时提到了特定属性的处理,如ro.boot.*和ro.product.*等。
摘要由CSDN通过智能技术生成

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.cpp
  • property_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()
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xhBruce

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值