1. Android系统属性机制解析
在Android系统中,系统属性(System Properties)是一个全局的键值对存储机制,用于在系统各个组件之间共享配置信息和运行时状态。系统属性主要分为两类:
- ro属性(read-only):以"ro."开头的属性,通常用于存储设备硬件信息、系统版本等固定配置,理论上只能在系统启动阶段由init进程设置一次
- rw属性(read-write):其他普通属性,可以在运行时动态修改
系统属性的实现核心位于system/core/init/property_service.cpp文件中,其中最关键的是PropertySet函数,它负责处理所有属性设置请求。当任何进程尝试设置属性时,都会经过这个函数的校验逻辑。
关键点:Android的安全模型设计决定了ro属性应该是不可变的,这是为了防止关键系统配置被恶意篡改。但在某些特殊开发场景下,我们确实需要突破这个限制。
2. 修改ro属性的实现方案
2.1 原始代码分析
在Android 16(对应Android 4.1 Jelly Bean)的原始代码中,property_service.cpp对ro属性的处理逻辑如下:
cpp复制static std::optional<uint32_t> PropertySet(const std::string& name, const std::s
prop_info* pi = (prop_info*)__system_property_find(name.c_str());
if (pi != nullptr) {
// ro.* properties are actually "write-once".
if (StartsWith(name, "ro.")) {
return PROP_ERROR_READ_ONLY_PROPERTY;
}
}
// ...其他逻辑
}
这段代码明确检查属性名是否以"ro."开头,如果是则直接返回PROP_ERROR_READ_ONLY_PROPERTY错误,阻止修改。
2.2 修改方案实现
要让系统允许修改ro属性,我们需要修改PropertySet函数的校验逻辑。以下是具体修改方法:
- 首先定位到
system/core/init/property_service.cpp文件 - 找到
PropertySet函数中的ro属性检查代码块 - 修改校验逻辑,有两种常见方案:
方案一:完全移除ro属性检查
diff复制- if (StartsWith(name, "ro.")) {
- return PROP_ERROR_READ_ONLY_PROPERTY;
- }
方案二:条件性绕过检查(推荐)
diff复制+ if (StartsWith(name, "ro.") && !IsDebugBuild()) {
+ return PROP_ERROR_READ_ONLY_PROPERTY;
+ }
方案二更为安全,它通过IsDebugBuild()判断当前是否为调试版本,只在正式版中保持ro属性不可修改。这需要额外实现IsDebugBuild()函数。
2.3 针对RK3576平台的适配
对于RK3576这类嵌入式平台,可能需要额外的修改:
- 检查平台特定的属性初始化代码
- 确认内核配置是否支持属性服务修改
- 可能需要调整selinux策略,允许属性修改操作
典型修改示例:
cpp复制// 在RK3576平台特定初始化代码中添加
if (IsRockchipPlatform()) {
property_override("ro.debuggable", "1");
}
3. 编译与验证步骤
3.1 代码修改后的编译
- 执行完整系统编译:
bash复制source build/envsetup.sh
lunch rk3576_userdebug # 根据实际目标选择
make -j8
- 单独编译init模块(快速验证):
bash复制mmm system/core/init
3.2 修改效果验证
验证ro属性是否可修改:
bash复制# 尝试修改ro属性
setprop ro.debuggable 1
# 检查属性值
getprop ro.debuggable
预期输出应为修改后的值"1"。如果仍然无法修改,可能需要:
- 检查selinux是否阻止了操作:
bash复制dmesg | grep avc
- 确认修改的代码确实被编译进去:
bash复制strings /system/bin/init | grep "ro\."
4. 注意事项与风险控制
4.1 安全性考虑
- 生产环境风险:此修改会降低系统安全性,绝对不要在正式发布的固件中使用
- selinux策略:可能需要同步调整selinux规则,例如:
te复制allow system_server default_prop:property_service set;
4.2 兼容性问题
-
版本差异:不同Android版本中property_service的实现可能有差异
- Android 8.0+使用了新的属性服务架构
- Android 10+引入了更严格的属性保护
-
厂商定制:各厂商可能修改了属性服务逻辑,需要检查:
bash复制git grep "ro\." -- hardware/
4.3 最佳实践建议
-
使用属性替代方案:
cpp复制// 代替直接修改ro属性 property_override("ro.special.mode", "1"); -
开发完成后恢复原始代码:
diff复制- if (StartsWith(name, "ro.")) { + if (StartsWith(name, "ro.") && !IsDebugBuild()) {
5. 深度技术原理
5.1 属性服务工作机制
Android属性系统的核心组件:
- init进程:作为属性服务的管理者
- 共享内存区域:存储所有属性键值对
- property_service:处理属性设置请求
- libcutils:提供属性访问API
关键调用流程:
code复制setprop -> libcutils -> property_service -> init进程
5.2 ro属性的特殊处理
ro属性在以下阶段被设置:
- 早期初始化:在
init.rc中通过setprop设置 - 硬件抽象层:HAL模块设置的硬件属性
- 厂商初始化:
vendor_init中设置的厂商属性
修改ro属性可能影响:
- 系统组件的初始化顺序
- 安全启动验证流程
- 系统升级机制
5.3 属性持久化机制
修改后的ro属性默认不会持久化,重启后会恢复。如需持久化需要:
- 修改
default.prop或build.prop - 在
init.rc中添加设置命令 - 使用
property_override接口
6. 常见问题排查
6.1 修改无效问题
现象:代码修改后ro属性仍然不可修改
排查步骤:
-
确认修改的代码文件是否正确:
bash复制
find . -name property_service.cpp -
检查编译产物是否包含修改:
bash复制
arm-linux-androideabi-objdump -S out/target/product/rk3576/symbols/system/bin/init > init.asm -
验证selinux策略:
bash复制
adb shell su root dmesg | grep property
6.2 系统稳定性问题
现象:修改ro属性后系统出现异常
解决方案:
-
检查依赖该属性的服务:
bash复制grep -r "ro\." /system/etc/init/ -
回滚属性修改:
bash复制
resetprop ro.example.property -
查看系统日志:
bash复制
logcat -b all | grep -i property
6.3 厂商定制冲突
现象:在特定设备上修改无效
解决方法:
-
检查厂商覆盖实现:
bash复制grep -r "property_service" hardware/ -
查找设备特定初始化:
bash复制find . -name "*init*.rc" | xargs grep "ro\." -
联系厂商获取修改指导
7. 高级技巧与扩展
7.1 动态属性监控
可以监控属性变化用于调试:
cpp复制int callback(const char* name, const char* value, void* cookie) {
LOG(INFO) << "Property changed: " << name << "=" << value;
return 0;
}
__system_property_add_callback(callback, nullptr);
7.2 属性访问控制
实现精细化的属性访问控制:
cpp复制bool IsAllowedProperty(const std::string& name) {
if (name == "ro.secure") return false;
return true;
}
7.3 属性修改日志
记录所有属性修改操作:
diff复制+ LOG(INFO) << "Property set: " << name << "=" << value;
if (pi != nullptr) {
在开发过程中,我发现在RK3576平台上修改ro属性后,某些厂商服务会出现异常行为。通过分析发现这些服务在启动时缓存了ro属性值,修改后需要重启服务才能生效。这提醒我们在修改关键属性时,需要考虑依赖该属性的所有服务。