平常在Android系统开发的过程中,我们经常会遇到需要属性来触发一些事件或者保存一些值,这时候我们需要用到系统属性,系统属性可以说是贯穿整个Android系统的一个重要知识点。
系统属性
在android 系统中,为统一管理系统的属性,设计了一个统一的属性系统。
- 每个属性都有一个名称和值,他们都是字符串格式;
- 属性被大量使用在Android系统中,用来记录系统设置或进程之间的信息交换;
- 属性是在整个系统中全局可见的;每个进程可以get/set属性。
- 在编译的过程中会将各种系统参数汇总到build.prop 以及default.prop这两个文件中,主要属性集中在build.prop中。
系统在开机后将读取配置信息并构建共享缓冲区,加快查询速度。另外一个方面,SettingsProvider会在系统第一次初始化时(刷机第一次启动)后,将从Defaults.xml中读取数据然后写入数据库Settings.db 目录,并构建一个缓冲系统供其他应用查询。
属性分类
系统属性根据不同的应用类型,一般分为不可变型,持久型,网络型,启动和停止服务等
- 不可变型
属性名称以“ro.”开头,那么这个属性被视为只读属性,一旦设置,属性值不能改变。 - 持久型
属性名称以“persist.”开头,当设置这个属性时,其值也将写入/data/property,这种属性是支持改变值的,因此在日常开发中,经常会用到这个类型的属性定义。 - 网络型
属性名称以“net.”开头,当设置这个属性时,“net.change”属性将会自动设置,以加入到最后修改的属性名( netresolve模块的使用这个属性来追踪在net.*属性上的任何变化)。 - 启动和停止服务
属性“ ctrl.start ”和“ ctrl.stop ”是用来启动和停止服务。这个服务指的不是Android日常开发里的Service,他指代的是系统底层的服务,每一项服务必须在init.*.rc脚本中定义。系统启动时,与init守护进程将解析init.rc和启动属性服务,一旦收到设置“ ctrl.start ”属性的请求,属性服务将使用该属性值作为服务名找到该服务,启动该服务。这项服务的启动结果将会放入“ init.svc.<服务名>“属性中 ,客户端应用程序可以轮询那个属性值,以确定结果。
属性的定义
属性的定义一般在Android源码的mk文件以及init.*.rc脚本中定义,一般位置处于device/amlogic/产品名 目录下,amlogic代表平台,不同平台目录名字不一样,在这个目录下表示的一般都是关于这个产品的定义,可以通过这篇文章了解下:理解build系统
在这个目录下的mk文件以及rc脚本中就可以定义我们需要的属性值:
- mk文件中定义属性值,如下图:
一般是在PRODUCT_PROPERTY_OVERRIDES后添加自己想定义的属性值和初始值。
在mk文件中定义的属性值如果是persist开头的话是支持修改属性的,而且是全局的,因此一般我们会自定义persist开头的属性值来触发一些服务或者保存一些全局相关的值。
- rc脚本中定义属性值
在rc脚本中定义属性值的话,这种属性值每次开机后就会重置成定义的默认值,因为每次开机rc脚本都会跑一次,这个就适用于需要开机重置的属性,定义方法如下:
in boot
setprop sys.usb.configfs 1
注意:属性定义但是编译完了,你会发现属性是可以找到的,但是属性你修改不了,这个的话主要原因是权限问题,虽然你是root权限,但是需要使用的话还是需要给属性值定义好权限,位置在system/sepolicy目录(这个目录就是selinux权限相关的一些处理)下的private/property_contexts 以及prebuilts/api/28.0/public/property_contexts目录下定义属性的类型和权限。比如:
persist.flag.code u:object_r:exported_system_radio_prop:s0 exact int
persist.flag.country u:object_r:exported_system_radio_prop:s0 exact string
上面的代码表示定义属性值的类型分别为int和string,权限分组的话system权限可以有rw权限,就是有系统应用权限的可以修改属性。如果还是有问题的话,那么可能需要在system/core/目录下修改init/stable_properties.h文件内容,kExportedActionableProperties函数里面添加上自己的属性定义:
static const std::set<std::string> kExportedActionableProperties = {
"persist.sys.zram_enabled",
"persist.flag.code", //增加属性值
"persist.flag.country" //增加属性值
}
属性位置
版本编译好后,属性值的一般位置在:
\ default.prop // 手机厂商自己定制使用
\system\build.prop // 系统属性主要存放处
\system\default.prop default properties // 有存放与security 相关的属性
\data\local.prop
\data\property\persistent_properties //保存着属性名称以“persist.”开头的属性值,用户的persist 开头的属性都会保存副本在这个目录下
属性获取和修改
既然属性定义了,那么自然是可以获取和修改,但是要注意的是ro.开头的属性一般是定义产品的关键内容信息,比如产品名,版本等,所以是不能在应用中修改的,只能在源码中修改定义。
- adb命令获取和修改属性值
adb shell getprop 属性值 //获取属性值信息
adb shell setprop 属性值参数 //设定属性值参数
- Android应用获取和修改属性
//通过反射设置系统属性值
public static void setProperty(String key, String value) {
try {
Class<?> c = Class.forName("android.os.SystemProperties");
Method set = c.getMethod("set", String.class, String.class);
set.invoke(c, key, value);
} catch (Exception e) {
e.printStackTrace();
}
}
//通过反射获取系统属性值
public static String getProperty(String key, String defaultValue) {
String value = defaultValue;
try {
Class<?> c = Class.forName("android.os.SystemProperties");
Method get = c.getMethod("get", String.class, String.class);
value = (String) (get.invoke(c, key, "unknown"));
} catch (Exception e) {
e.printStackTrace();
}
return value;
}