RK3568 Android系统客制化动态替换ro任意属性

简介: RK3568 Android系统客制化动态替换ro任意属性

在Android系统开发中,经常会遇到需要动态修改系统属性的情况。尤其是对于那些标记为只读的属性,修改它们可能会比较困难。本文将以RK3568 Android11为例,介绍如何动态替换任意的ro属性以及在此过程中遇到的问题和解决方案。

需求背景

在Android系统中,属性经常用于配置信息,例如设备型号、硬件版本等。有时,为了适应不同的硬件或软件需求,我们可能需要在系统运行时动态修改这些属性,而不是重新编译整个系统。

方案思路

我的解决方案是在系统启动时,加载一个自定义的属性文件,该文件中的属性将覆盖系统中已存在的属性。这样,我们就可以在不修改系统源代码的情况下,动态地修改任意属性。

Android 11的Property加载流程

  1. 启动init进程:Android系统启动时,首先启动的是init进程。这是系统的第一个进程,负责初始化系统环境和启动其他系统服务。
  2. 加载默认属性init进程首先加载/system/etc/prop.default文件中的属性。这些属性通常包括硬件和系统的基本配置。
if (!load_properties_from_file("/system/etc/prop.default", nullptr, &properties)) {
    // Try recovery path
    if (!load_properties_from_file("/prop.default", nullptr, &properties)) {
        // Try legacy path
        load_properties_from_file("/default.prop", nullptr, &properties);
    }
}
  1. 加载其他属性文件:除了默认属性文件,init进程还会加载其他多个属性文件,如/system/build.prop/vendor/build.prop等。这些文件中的属性可以覆盖默认属性文件中的属性。
load_properties_from_file("/system/build.prop", nullptr, &properties);
load_properties_from_file("/vendor/build.prop", nullptr, &properties);
  1. 加载设备特定属性:为了支持多种硬件配置,Android 11引入了设备特定的属性文件,如/odm/build.prop/product/build.prop等。这些文件中的属性可以根据具体的硬件配置进行定制。
load_properties_from_file("/odm/build.prop", nullptr, &properties);
load_properties_from_file("/product/build.prop", nullptr, &properties);
  1. 属性覆盖:在加载属性时,后加载的属性会覆盖先加载的属性。这意味着,如果多个属性文件中都定义了同一个属性,那么最后加载的文件中的属性值将被使用。

为什么自定义属性可以覆盖默认属性?

这是因为Android的属性加载机制是基于后加载的属性覆盖先加载的属性的原则设计的。这种设计允许开发者和OEM厂商在不修改系统源代码的情况下,通过添加或修改属性文件来定制系统配置。

例如,我们可以在/product/customize.prop中定义一个属性ro.product.system.model=rk3568_custom。由于这个文件是在其他属性文件之后加载的,所以这个属性会覆盖在之前的文件中定义的同名属性。

实现步骤:

  1. 选择自定义属性文件的位置:考虑到系统的启动顺序和分区挂载情况,我们选择将自定义属性文件放在/product分区,因为这个分区在系统的早期启动阶段就已经被挂载,所以init进程可以在启动时访问它。我们将自定义属性文件命名为customize.prop
  2. 修改属性加载代码:在system/core/init/property_service.cpp文件中,找到PropertyLoadBootDefaults函数。在该函数中,我们在加载其他属性文件之后,添加了加载我们的自定义属性文件的代码。
void PropertyLoadBootDefaults() {
    // TODO(b/117892318): merge prop.default and build.prop files into one
    // 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 (!load_properties_from_file("/system/etc/prop.default", nullptr, &properties)) {
        // Try recovery path
        if (!load_properties_from_file("/prop.default", nullptr, &properties)) {
            // Try legacy path
            load_properties_from_file("/default.prop", nullptr, &properties);
        }
    }
    load_properties_from_file("/system/build.prop", nullptr, &properties);
    load_properties_from_file("/system_ext/build.prop", nullptr, &properties);
    load_properties_from_file("/vendor/default.prop", nullptr, &properties);
    load_properties_from_file("/vendor/build.prop", nullptr, &properties);
    if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_Q__) {
        load_properties_from_file("/odm/etc/build.prop", nullptr, &properties);
    } else {
        load_properties_from_file("/odm/default.prop", nullptr, &properties);
        load_properties_from_file("/odm/build.prop", nullptr, &properties);
    }
    load_properties_from_file("/product/build.prop", nullptr, &properties);
    load_properties_from_file("/factory/factory.prop", "ro.*", &properties);
    if (access(kDebugRamdiskProp, R_OK) == 0) {
        LOG(INFO) << "Loading " << kDebugRamdiskProp;
        load_properties_from_file(kDebugRamdiskProp, nullptr, &properties);
    }
    // 加载自定义的prop文件 start
    //const char* customPropPath = "/mnt/private/customize.prop";
    const char* customPropPath = "/product/customize.prop";
    if (access(customPropPath, R_OK) == 0) {
        LOG(INFO) << "[custom_prop] Loading " << customPropPath;
        load_properties_from_file(customPropPath, nullptr, &properties);
    } else {
        LOG(INFO) << customPropPath << " not found, skipping.[custom_prop]";
    }
    // 加载自定义的prop文件  end
    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_derive_build_fingerprint();
    update_sys_usb_config();
}

如何测试:

我们在customize.prop文件中设置了ro.product.system.model=rk3568_custom。启动系统后,我们使用getprop ro.product.system.model命令,确实得到了rk3568_custom,这证明我们的修改是成功的。

  1. 属性验证:使用getprop命令验证属性是否已被正确加载。
  2. 系统功能测试:确保修改后的系统可以正常启动,并运行各种应用程序。
  3. 日志检查:通过logcat命令,检查系统日志,确保没有与属性加载相关的错误或警告。

遇到的问题:

  1. 分区挂载问题:最初,我们尝试将自定义属性文件放在/mnt/private分区。但在系统启动早期,该分区尚未挂载,导致init进程无法访问。因此,我们选择了/product分区。
  2. 属性覆盖问题:由于属性加载的顺序,后加载的属性会覆盖先加载的属性。因此,我们确保自定义属性文件是在其他属性文件之后加载的。

结论

通过上述方法,我们成功地实现了在RK3568 Android12系统中动态替换任意的ro属性。这为Android系统开发提供了更大的灵活性,使我们能够更容易地适应不同的硬件和配置需求。

相关文章
|
5月前
|
Linux 测试技术 语音技术
【车载Android】模拟Android系统的高负载环境
本文介绍如何将Linux压力测试工具Stress移植到Android系统,用于模拟高负载环境下的CPU、内存、IO和磁盘压力,帮助开发者优化车载Android应用在多任务并发时的性能问题,提升系统稳定性与用户体验。
384 6
|
5月前
|
Java 数据库 Android开发
基于Android的电子记账本系统
本项目研究开发一款基于Java与Android平台的开源电子记账系统,采用SQLite数据库和Gradle工具,实现高效、安全、便捷的个人财务管理,顺应数字化转型趋势。
|
9月前
|
Android开发 开发者
Android自定义View之不得不知道的文件attrs.xml(自定义属性)
本文详细介绍了如何通过自定义 `attrs.xml` 文件实现 Android 自定义 View 的属性配置。以一个包含 TextView 和 ImageView 的 DemoView 为例,讲解了如何使用自定义属性动态改变文字内容和控制图片显示隐藏。同时,通过设置布尔值和点击事件,实现了图片状态的切换功能。代码中展示了如何在构造函数中解析自定义属性,并通过方法 `setSetting0n` 和 `setbackeguang` 实现功能逻辑的优化与封装。此示例帮助开发者更好地理解自定义 View 的开发流程与 attrs.xml 的实际应用。
257 2
Android自定义View之不得不知道的文件attrs.xml(自定义属性)
|
10月前
|
安全 搜索推荐 Android开发
Android系统SELinux安全机制详解
如此看来,SELinux对于大家来说,就像那位不眠不休,严阵以待的港口管理员,守护我们安卓系统的平安,维护这片海港的和谐生态。SELinux就这样,默默无闻,却卫士如山,给予Android系统一份厚重的安全保障。
335 18
|
存储 安全 Android开发
探索Android系统的最新安全特性
在数字时代,智能手机已成为我们生活中不可或缺的一部分。随着技术的不断进步,手机操作系统的安全性也越来越受到重视。本文将深入探讨Android系统最新的安全特性,包括其设计理念、实施方式以及对用户的影响。通过分析这些安全措施如何保护用户免受恶意软件和网络攻击的威胁,我们希望为读者提供对Android安全性的全面了解。
|
IDE Java 开发工具
移动应用与系统:探索Android开发之旅
在这篇文章中,我们将深入探讨Android开发的各个方面,从基础知识到高级技术。我们将通过代码示例和案例分析,帮助读者更好地理解和掌握Android开发。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和技巧。让我们一起开启Android开发的旅程吧!
|
监控 Java Android开发
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
|
安全 Android开发 iOS开发
深入探讨Android与iOS系统的差异及未来发展趋势
本文旨在深入分析Android和iOS两大移动操作系统的核心技术差异、用户体验以及各自的市场表现,进一步探讨它们在未来技术革新中可能的发展方向。通过对比两者的开放性、安全性、生态系统等方面,本文揭示了两大系统在移动设备市场中的竞争态势和潜在变革。
|
XML Android开发 数据格式
Android中利用shape属性自定义设置Button按钮
Android中利用shape属性自定义设置Button按钮
545 0
|
Android开发
Android 获取include标签中的控件属性并设置事件
Android 获取include标签中的控件属性并设置事件
339 0