需要注意的是对name和value的length是有限制的,name的最大长度是31,value最大长度是91,具体定义如下:
//frameworks/base/core/java/android/os/SystemProperties.java
public class SystemProperties
{
public static final int PROP_NAME_MAX = 31;
public static final int PROP_VALUE_MAX = 91;
...
private static native String native_get(String key);
private static native void native_set(String key, String def);
/**
* Get the value for the given key.
* @return an empty string if the key isn't found
* @throws IllegalArgumentException if the key exceeds 32 characters
*/
public static String get(String key) {
if (key.length() > PROP_NAME_MAX) {
throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
}
return native_get(key);
}
...
/**
* Set the value for the given key.
* @throws IllegalArgumentException if the key exceeds 32 characters
* @throws IllegalArgumentException if the value exceeds 92 characters
*/
public static void set(String key, String val) {
if (key.length() > PROP_NAME_MAX) {
throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
}
if (val != null && val.length() > PROP_VALUE_MAX) {
throw new IllegalArgumentException("val.length > " +
PROP_VALUE_MAX);
}
native_set(key, val);
}
...
}
在调用get或set时,都是通过调用native方法去操作的,开始本来想一笔带过的,还是看看native方法中的具体流程吧,如果不感兴趣可以直接看第三条
ps:在调用SystemProperties.set时所在的apk uid必须在system group,否则设置属性会报错,在manifest配置下行:
android:sharedUserId="android.uid.system"
//frameworks/base/core/jni/android_os_SystemProperties.cpp
static const JNINativeMethod method_table[] = {
{ "native_get", "(Ljava/lang/String;)Ljava/lang/String;",
(void*) SystemProperties_getS },
{ "native_get", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
(void*) SystemProperties_getSS },
{ "native_get_int", "(Ljava/lang/String;I)I",
(void*) SystemProperties_get_int },
{ "native_get_long", "(Ljava/lang/String;J)J",
(void*) SystemProperties_get_long },
{ "native_get_boolean", "(Ljava/lang/String;Z)Z",
(void*) SystemProperties_get_boolean },
{ "native_set", "(Ljava/lang/String;Ljava/lang/String;)V",
(void*) SystemProperties_set },
{ "native_add_change_callback", "()V",
(void*) SystemProperties_add_change_callback },
};
int register_android_os_SystemProperties(JNIEnv *env)
{
return RegisterMethodsOrDie(env, "android/os/SystemProperties", method_table,
NELEM(method_table));
}
register_android_os_SystemProperties方法是在AndroidRuntime.cpp中调用的,RegisterMethodsOrDie可以简单的理解为把method_table数组里的方法一一对应起来。在android_os_SystemProperties.cpp中可以发现最终实现是不区分SystemProperties_get_int或 SystemProperties_getS,基本所有的方法都是调用property_get和property_set方法来实现的
//system/core/libcutils/properties.c
int property_get(const char *key, char *value, const char *default_value)
{
int len;
len = __system_property_get(key, value);
if(len > 0) {
return len;
}
if(default_value) {
len = strlen(default_value);
if (len >= PROPERTY_VALUE_MAX) {
len = PROPERTY_VALUE_MAX - 1;
}
memcpy(value, default_value, len);
value[len] = '\0';
}
return len;
}
int property_set(const char *key, const char *value)
{
return __system_property_set(key, value);
}
进程启动后数据已经将系统属性数据读取到相应的共享内存中,保存在全局变量__system_property_area__,具体操作在system_properties.cpp中
//bionic/libc/bionic/system_properties.cpp
int __system_property_get(const char *name, char *value)
{
const prop_info *pi = __system_property_find(name);
if (pi != 0) {
//数据已经存储在内存中__system_property_area__ 等待读取完返回
return __system_property_read(pi, 0, value);
} else {
value[0] = 0;
return 0;
}
}
设置属性通过异步socket通信,向property_service发送消息
int __system_property_set(const char *key, const char *value)
{
if (key == 0) return -1;
if (value == 0) value = "";
if (strlen(key) >= PROP_NAME_MAX) return -1;
if (strlen(value) >= PROP_VALUE_MAX) return -1;
prop_msg msg;
memset(&msg, 0, sizeof msg);
msg.cmd = PROP_MSG_SETPROP;
strlcpy(msg.name, key, sizeof msg.name);
strlcpy(msg.value, value, sizeof msg.value);
const int err = send_prop_msg(&msg);
if (err < 0) {
return err;
}
return 0;
}
static int send_prop_msg(const prop_msg *msg)
{ //sokcet 通信 /dev/socket/property_service
const int fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (fd == -1) {
return -1;
}
//static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
const size_t namelen = strlen(property_service_socket);
sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
strlcpy(addr.sun_path, property_service_socket, sizeof(addr.sun_path));
addr.sun_family = AF_LOCAL;
socklen_t alen = namelen + offsetof(sockaddr_un, sun_path) + 1;
if (TEMP_FAILURE_RETRY(connect(fd, reinterpret_cast(&addr), alen)) < 0) {
close(fd);
return -1;
}
const int num_bytes = TEMP_FAILURE_RETRY(send(fd, msg, sizeof(prop_msg), 0));
...
close(fd);
return result;
}
property_service是在init进程调用start_property_service启动的,在property_service.cpp中
//system/core/init/property_service.cpp
void start_property_service() {
//创建socket
property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
0666, 0, 0, NULL);
if (property_set_fd == -1) {
ERROR("start_property_service socket creation failed: %s\n", strerror(errno));
exit(1);
}
//监听socket
listen(property_set_fd, 8);
register_epoll_handler(property_set_fd, handle_property_set_fd);
}
还是在property_service.cpp的handle_property_set_fd()处理对应属性
static void handle_property_set_fd()
{
//等待建立通信
if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
return;
}
/获取套接字相关信息 uid gid
if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
close(s);
ERROR("Unable to receive socket options\n");
return;
}
...
//接收属性设置请求消息
r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT));
//处理消息
switch(msg.cmd) {
case PROP_MSG_SETPROP:
msg.name[PROP_NAME_MAX-1] = 0;
msg.value[PROP_VALUE_MAX-1] = 0;
//检查属性名是否合法
if (!is_legal_property_name(msg.name, strlen(msg.name))) {
ERROR("sys_prop: illegal property name. Got: \"%s\"\n", msg.name);
close(s);
return;
}
getpeercon(s, &source_ctx);
//处理ctl.开头消息
if(memcmp(msg.name,"ctl.",4) == 0) {
// Keep the old close-socket-early behavior when handling
// ctl.* properties.
close(s);
//检查权限,处理以ctl开头的属性
if (check_control_mac_perms(msg.value, source_ctx, &cr)) {
handle_control_message((char*) msg.name + 4, (char*) msg.value);
} else {
ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n",
msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);
}
} else {
//检查权限,设置对应的属性
if (check_mac_perms(msg.name, source_ctx, &cr)) {
property_set((char*) msg.name, (char*) msg.value);
} else {
ERROR("sys_prop: permission denied uid:%d name:%s\n",
cr.uid, msg.name);
}
close(s);
}
...
}
}
不继续看了,后面的坑还有很多,考虑到后面还有几个方面没讲,简单说下property_set最后是调用了property_set_impl实现的,有兴趣的可以继续去跟踪
PRODUCT_PROPERTY_OVERRIDES += \
persist.timed.enable=true \
persist.timed.enable=true \
... \
key=value
//system/core/rootdir/init.rc
on property:sys.boot_from_charger_mode=1
trigger late-init
# Load properties from /system/ + /factory after fs mount.
on load_system_props_action
load_system_props #定义在property_service.cpp
on load_persist_props_action
load_persist_props #定义在property_service.cpp
start logd
start logd-reinit
# Mount filesystems and start core system services.
on late-init
# Load properties from /system/ + /factory after fs mount. Place
# this in another action so that the load will be scheduled after the prior
# issued fs triggers have completed.
trigger load_system_props_action
# Load persist properties and override properties (if enabled) from /data.
trigger load_persist_props_action
当属性值sys.boot_from_charger_mode为1时,会触发late-init,在late-init又会触发load_system_props_action和load_persist_props_action,具体看看property_service.cpp这两个方法对应干啥了
//system/core/init/property_service.cpp
void load_system_props() {
load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);//加载system/build.prop
load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL);//加载vendor/build.prop
load_properties_from_file(PROP_PATH_FACTORY, "ro.*");//加载factory/factory.prop
load_recovery_id_prop();//加载recovery相关prop
}
void load_persist_props(void) {
load_override_properties();//如果"ro.debuggable"为1加载data/local.prop里的属性
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();//加载/data/property里的persistent properties
}
当同一属性在多个文件中都有配置,先加载的会被后加载的覆盖。