Android系统prop属性的研究与分析
在程序开发的时候,往往会共享一些数据信息,有一个环境变量或者属性下面几种情况:
1.该变量在多处需要使用,并且是跨进程或者跨线程的。
2.该环境变量一般只需读取一次,不需要频繁保存。
3.同时这个变量信息在关机重启后任然可以保存。
对于这些需求,通常的做法是将这些信息保存到一个文件中,通过对该文件的读写来提取和保存信息,这些信息的数据量都比较小。这种方法是可以的,但是不是很系统完善,而且当需要读取信息时都需要进行一次文件的io操作,这就很费时和浪费系统资源;还有一种情况,就是一个变量信息,开机启动的时只需从flash中读取一次,在系统运行时很少对它进行修改,所以这种信息保存到内存更显得合适。
Window中有注册表这样完善的模块对少量配置信息进行存储,android中就有类似的Prop模块。Prop模块存储着系统运行的很多配置信息,当程序运行时需要某种系统状态时,会到该模块中进行读取。Prop模块本质上来说,是系统运行时内存中保存的一块数据区,读写数据都是对这一块区域进行操作;好处是读写速度快,数据跨进程共享,缺点是突然断电会丢失数据;当然Prop也能保存数据,这个在后面提到。
系统中的一些有用的配置信息:
Android的启动后,在property_service.c的property_init中完成prop的初始化。系统中存在着几个文件,如build.prop和default.prop等,这些文件在系统构建时候生成的,里面包含很多系统配置信息。系统开机时回去加载这些文件中的信息并保存到prop模块中去,以便利用其它程序进行使用。
例如在build.prop中有如下信息:
dalvik.vm.heapstartsize=5m
dalvik.vm.heapgrowthlimit=96m
dalvik.vm.heapsize=256m
dalvik.vm.heaptargetutilization=0.75
dalvik.vm.heapminfree=512k
dalvik.vm.heapmaxfree=2m
虚拟机的堆栈大小以及其它属性。
persist.sys.timezone=Asia/Shanghai
时区信息。
ro.build.version.codename=REL
ro.build.version.release=4.2.2
ro.build.date=Fri Dec 26 15:56:10 UTC 2014
ro.build.date.utc=1419609370
构建信息。
ro.product.cpu.abi=armeabi-v7a
ro.product.cpu.abi2=armeabi
ro.product.manufacturer=unknown
ro.product.locale.language=en
ro.product.locale.region=US
Cpu信息,默认语言设置。
dalvik.vm.stack-trace-file=/data/anr/traces.txt
虚拟机的调试信息保存路径。
这些动作都是在init.rc中完成的,该过程会调用property_service.c中的start_property_service函数,在该函数中完成以下文件的加载:
#define PROP_PATH_RAMDISK_DEFAULT "/default.prop"
#define PROP_PATH_SYSTEM_BUILD "/system/build.prop"
#define PROP_PATH_SYSTEM_DEFAULT "/system/default.prop"
#define PROP_PATH_LOCAL_OVERRIDE "/data/local.prop"
同时会调用load_persistent_properties函数,该函数会/data/property/中寻找用户的保存设置。
Env环境变量中有一个ANDROID_PROPERTY_WORKSPACE变量,该变量中存储着prop内存区域的大小,这个是在init_property_area中完成的。
Prop对应的Java接口:
Prop模块中可以set和get进行相应的操作,这些在property_service.c中有property_set和property_get接口进行操作。Android的JAVA层也有对应的接口,这个应用到android.os.SystemProperties类中,该类的Set和Get直接进行设置和获取,这些接口方法追到底层也是使用property_set函数完成的。但是这些接口并没有直接开放给应用,在使用set接口时必须要有系统权限。
SystemProperties类的访问必须要有系统权限,并且应用的uid必须是系统id:1000或者为root:0。因为set和get操作不同,set时该操作建立了一个socket管道通过发cmd出去完成的,服务端接收cmd同时比较权限,如:
if (uid == AID_SYSTEM || uid == AID_ROOT)
return check_control_mac_perms(name, sctx);
只有权限通过以后才能set。而get没有权限检查,不过试想也正常,如果谁都能进行修改,那这黑客也太好当了。
设置键值名时需要注意的地方:
在进行设置时,包含两个参数,变量名和变量值,形如:[[key]]: [[value]]。如果原来没有对应的key值,那么就会在该模块中创建一个新的键值,但是对于该键名有一些要求。使用时最好键名容易区别,不与其它键名冲突。如果属性名称以“ro.”开头,那么这个属性被视为只读属性。一旦设置,属性值不能改变。这个动作是在property_service.c中的property_set函数中完成的,有如下代码:
if(!strncmp(name, "ro.", 3)) return -1;
如果是以“persist.”开头,当设置这个属性时,其值也将写入/data/property/目录中,下次开机该值任然存在,该文件的load_persistent_properties函数中,完成/data/property/的属性加载与设置。
如果属性名以“net.change”开头那么其值中必须以“net.”开头。例如键值名为[net.change]: 那么键值为[net.qtaguid_enabled]。
Shell中对应的prop操作命令:
在android的shell中也有对应的命令进行操作,有如下三个命令:
getprop [keyname]
Keyname为需要获取的键值名,如果没有参数则打印全部的键值信息。
setprop [keyname] [value]
Keyname为需要获取的键值名,value为设置的值,这个值为字符串。
watchprops
监听系统属性的变化,如果期间系统的属性发生变化则把变化的值显示出来。
在init.rc中也使用setprop来设置一些属性状态。
[本文是基于android4.2源码进行分析]
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。