Android 系统属性添加篇

添加属性,存储值实现

文章目录


前言 - 需求

实现添加属性的功能,了解属性添加机制,搞明白两种不同的添加方式和区别

参考资料

Android系统开发入门-3.添加系统属性
Framework 层Settings.System, Settings.Secure和Settings.Global存储及应用
RK-Android11-系统增加一个属性值

一、添加属性文件

比如我们在windows 电脑上面 cmd , getprop 获取到的属性 哪里来的? 这个需要搞清楚,如果我们把数据保存到我们看到的属性 getprop 里面的 key 对应的结果里面。

那么首先要解决的就是属性定义和属性配置,其次就是属性赋值来存储设置的值

比如如下 获取的属性:

1、在 .mk 文件中添加系统属性 (System Property)

这是底层系统级别的配置。

系统属性基础知识

定义说明-是什么

系统属性是Android系统的一个全局键值对数据库,主要用于原生层(C/C++/Native) 和 系统服务 之间的配置和通信。它通过 libcutils 库的 property_get property_set 函数来访问。常见的例子如ro.product.model(只读产品型号)、persist.sys.timezone (持久化时区)、ctl.start/ctl.stop (控制服务)。

如何添加

.mk 文件(通常是 device/<厂商>/<平台>/device.mk)中,使用 PRODUCT_PROPERTY_OVERRIDES 变量来定义或覆盖系统属性的默认值

java 复制代码
# 定义一个只读属性,通常在编译时确定
PRODUCT_PROPERTY_OVERRIDES += ro.vendor.my_custom_feature=enabled

# 定义一个可读写并持久化的属性初始值
PRODUCT_PROPERTY_OVERRIDES += persist.vendor.sys.debug_log=0
属性前缀说明
  • ro.:只读。一旦设置,值不能改变。
  • persist.:持久化。设置后会被保存到 /data/property 目录,重启后依然有效。
  • vendor./ctl. 等:其他前缀,没有特殊功能,主要用于命名空间分类。

优劣分析

优点

底层高效:直接在Native层读写,速度非常快,被大量用于系统初始化流程。

全局可见:所有进程(Java和Native)都可以读取。

启动顺序早:在 init 进程解析 init.rc 时就可使用,非常适合控制底层服务和守护进程的启动行为。

权限控制:设置属性需要特定的SELinux权限,相对安全。

缺点

  • 类型单一:只支持字符串值,应用层需要自己解析(如将 "1" 解析为 true)。
  • 不适合应用层大量使用:设计初衷并非用于应用配置,API设计也不友好(需要处理字符串)。
  • 写入权限严格:非系统级应用通常无法设置大多数属性,需要配置SELinux策略。

2、在 SettingsProvider 数据库中添加设置 (Settings.Global/Secure/System)

这是上层应用框架级别的配置。

定义说明-是什么

Android提供了一个名为 SettingsProvider 的系统应用,它维护了三个SQLite数据库来为其他应用存储配置信息。这些配置通过Content Provider暴露出来,供应用通过 Settings API 进行访问。

  • Global (Settings.Global): 所有用户共享的全局设置,通常需要系统权限(WRITE_SECURE_SETTINGS)才能修改。例如,设备名称、USB调试开关。
  • Secure (Settings.Secure): 每个用户的安全敏感设置。修改通常也需要系统权限。例如,默认输入法、受信任的凭据。
  • System (Settings.System): 每个用户的非敏感系统偏好设置。普通应用(在同一用户下)也可以读写自己的包名相关的设置。例如,屏幕亮度、铃声选择。

如何添加

frameworks/base/packages/SettingsProvider/res/values/defaults.xml中添加条目的默认值。

java 复制代码
<resources>
    ...
    <!-- 在 defaults.xml 中 -->
    <string name="def_my_custom_setting" translatable="false">default_value</string>
    <integer name="def_my_custom_int_setting">1</integer>
    <bool name="def_my_custom_bool_setting">true</bool>
</resources>
插入数据库

frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java loadGlobalSettings, loadSecureSettings, 或 loadSystemSettings 方法中,将默认值插入到对应的数据库表中。

java 复制代码
// 在 DatabaseHelper.java 的 loadGlobalSettings 方法中
loadStringSetting(stmt, Settings.Global.MY_CUSTOM_SETTING,
        R.string.def_my_custom_setting);
loadIntegerSetting(stmt, Settings.Global.MY_CUSTOM_INT_SETTING,
        R.integer.def_my_custom_int_setting);
		
定义键名

frameworks/base/core/java/android/provider/Settings.java 中为你的新设置定义一个公开的静态常量 String

java 复制代码
public static final String MY_CUSTOM_SETTING = "my_custom_setting";

优劣分析

优点:

  • 类型丰富:支持String, Int, Float, Long等多种数据类型,应用层使用方便。

  • API友好:提供了标准、易用的CRUD API (Settings.System.putInt(), Settings.Secure.getString() 等)。

  • 权限模型清晰:通过Android标准的权限机制控制访问,管理方便。

  • 面向应用层:是应用和系统服务保存和读取配置的首选方式。

    缺点:

  • 启动时机较晚:需要等 SettingsProvider 这个系统应用启动并加载数据库完成后才能使用,不能在非常早期的启动阶段(如 init 阶段)依赖。

  • 性能开销:基于Content Provider的数据库操作,比直接读写内存中的系统属性要慢。

  • Native层不友好:Native代码访问Settings数据库比较麻烦,需要通过JNI调用Java API或直接查询SQLite

3、对比总结与如何选择

特性 系统属性 (System Property) Settings 数据库 (Settings.Global/Secure/System)
层级 底层 (Init, Native) 上层 (Framework, App)
存储机制 内存映射文件 (/dev/properties) SQLite 数据库
数据类型 仅字符串 String, Int, Float, Long, Bool
访问API SystemProperty.get()/set() (Java), property_get()/set() (C++) Settings.Global/Secure/System.getXXX()/putXXX()
权限控制 SELinux 策略 Android 权限 (e.g., WRITE_SECURE_SETTINGS)
持久化 需显式使用 persist. 前缀 自动持久化
启动阶段 非常早 (Init 阶段) 较晚 (After SettingsProvider 启动)
适用场景 控制底层服务、驱动参数、早期启动配置 应用偏好、用户设置、系统功能开关

二、案例实战-添加系统属性

比如我在系统里面添加几个属性 通过系统属性方式实现,如下:那么如何实现

java 复制代码
[persist.fise.custom.usbdata]: [0]
[persist.fise.custom.usbmode]: [0]
[persist.fise.custom.wifidata]: [0]
[persist.fise.custom.wifimode]: [0]

找到.mk 修改的位置并配置属性

强烈建议先看看参考资料,或者 网上一些资料,然后自己去找配置文件,或者 在源码里面通过指定的key 来搜索配置文件.mk 位置。

Android系统开发入门-3.添加系统属性
RK-Android11-系统增加一个属性值

比如如下,通过属性:persist.sys.boot.reason 在源码里面查找,找到了配置文件.mk 位置,然后根据已有的写法配置自己的 属性

编译后,查看是否成功,如下:显示已经成功了的

三、读取系统属性-SystemProperties

前面是设置系统属性,如何读取呢?

源码查看

源码位置: /frameworks/base/core/java/android/os/SystemProperties.java

源码如下:

java 复制代码
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.os;

// Stub for cutting dependency from sysprop_library to framework.jar
public class SystemProperties {
    public static String get(String key) {
        return null;
    }
    public static void set(String key, String val) {
    }
    private SystemProperties() {
    }
}

读取方法

直接看看系统读取方法,参考:

总结

为什么再次罗列属性添加、读取 基本知识点? 实际开发中太多数据持久化的知识点运用了,为快速开发提炼基本知识技能。