Android Property
A property is an abstraction that can be used to represent a mutable value that is held in a host object.
作为一个系统服务(?)管理着系统的配置和状态,所有的这些系统配置和状态都是属性(Property)。
Property是键值对(K/V)形式,键值都是字符串类型。Android中很多应用和库直接或间接依赖于属性系统,并由此决定运行期的行为。例如:adbd进程通过属性来决定是否当前运行在模拟器中。更多例子可在init.rc中找到,如下图:
java.io.File.pathSeparator方法返回存储在属性服务中的值。
private String path;
static {
separatorChar = System.getProperty("file.separator", "/").charAt(0);
pathSeparatorChar = System.getProperty("path.separator", ":").charAt(0);
separator = String.valueOf(separatorChar);
pathSeparator = String.valueOf(pathSeparatorChar);
}
Property结构图:
属性读取进程(Property consumer)把这块共享内存映射到自己的进程空间,然后直接读取它。属性设置进程(Property setter)也加载这块共享内存到自己的进程空间。但它只能通过Unix Socket发属性给Property service,由Property service代表设置进程写入共享内存和属性文件(?)。
Property Service运行于init进程中。Init进程先创建一块共享内存,并把它的句柄fd存放在这块内存中,init进程通过mmap带MAP_SHARE标志的系统调用,把这块内存映射到它的虚拟空间中。最终这块内存所有的更新将被所有映射这块共量“ANDROID_PROPERTY_WORKSPACE”中,所有的进程包括属性设置进程和属性读取进程都将通过这个系统环境变量或得共享内存的句柄fd和大型,然后把这块内存映射到他们自己的虚拟空间。共享内存布局如下:
然后init进程从文件中加载属性。Property Service是在Property_service.c(/system/core/init)文件中写的。在init.c(/system/core/init)中会调用它的property_load_boot_defaults(),其实是加载的/default.prop。总共有如下:
#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"
他们会按顺序加载,后加载的会覆盖原先的值。
然后启动Property service。这里会创建一个Unix Socket服务器(/dev/socket/property_service)。最后init进入死循环(?),等待socket的连接请求。
在读取进程中,当它初始化libc库的时候,将会或得属性系统共享内存的句柄和大小(bionic /libc/bionic/libc_init_common.c __libc_init_common函数)。并把这块共享内存映射到自己的进程虚拟空间中(bionic/libc/bionic/system_properties.c __system_properties_init函数)。这样读取进程将会向访问普通内存一样访问属性系统的共享内存了。
Property不能被删除,一旦创建,只能被修改。
获取和设置属性:
1.Native代码
extern const char* property_get(const char *name);
extern int property_set(const char *name, const char *value);
使用时包含cutils/properties.h和链接libcutil库。
2.Java代码
System.getProperty和System.setProperty
Java版本存储把属性存在其它地方,不是上面的属性系统,而是JVM中的一个hash表来维护Java的属性。所以不能用Java的来设置系统属性,也不能用Native的方法来设置Java的属性。
Andrew指出android.os.SystemProperties可以操作Android系统属性(此类倾向于内部使用)。这个类通过JNI调用Native的property_get和property_set方法来获得和设置属性。
3.Shell脚本
Android提供了命令行工具setprop和getprop来设置和获取属性,可在脚本中使用
property_service.c中property_perms[]定义的是当前系统可用的所有属性的前缀,以及对应的存取权限UID。对属性设置要满足权限要求看,命名也要在定义的范围内。添加的bootanim({ "bootanim", AID_GRAPHICS, 0 })可以在init.rc中查看到。
service bootanim /system/bin/bootanimation
class main
user graphics
group graphics
disabled //不会自动启动
oneshot //只启动一次
因为服务必须在init.rc中定义。系统启动时,init守护进程将解析init.rc和启动属性服务,一旦收到设置“ctrl.start”属性的请求,属性服务根据属性值作为服务名自动改服务,启动结果会放在init.svc<服务名>属性中。
插一句:关于init.rc可以查看Android源码文件system/core/init/readme.txt
属性“ro.”开头,只读属性。
属性“persist.”开头,设置后值写入/data/property。
属性“net.”开头,设置后,net.change属性会自动设置,以加入到最后修改的属性名。Netresolve模块使用这个属性来追踪net.*上的任何变化。
属性“ctrl.start”和“ctrl.stop”用来启动和停止服务。
#define PA_COUNT_MAX 247 //系统最多能存247个属性
#define PROP_NAME_MAX 32 //Key最大长度
#define PROP_VALUE_MAX 92 //Value最大长度