Android4.4属性配置SystemProperties使用笔记
原创:https://www.jianshu.com/p/d39e55335cdf
DD_Dog关注
2019.07.30 09:30:45字数 363阅读 98
本文简单介绍SytemProperties的调用流程
涉及到的源文件:frameworks/base/core/java/android/os/SystemProperties.java
frameworks/base/core/jni/android_os_SystemProperties.cpp
system/core/libcutils/properties.c
bionic/libc/bionic/system_properties.c
一、frameworks层java接口
frameworks/base/core/java/android/os/SystemProperties.java
以set和get方法举例
//定义key和value的最大长度
public static final int PROP_NAME_MAX = 31;
public static final int PROP_VALUE_MAX = 91;
/**
* Get the value for the given key.
* @return if the key isn't found, return def if it isn't null, or an empty string otherwise
* @throws IllegalArgumentException if the key exceeds 32 characters
*/
public static String get(String key, String def) {
//判断key的长度
if (key.length() > PROP_NAME_MAX) {
throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
}
//调用JNI方法
return native_get(key, def);
}
/**
* 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);
}
//判断value的长度
if (val != null && val.length() > PROP_VALUE_MAX) {
throw new IllegalArgumentException("val.length > " +
PROP_VALUE_MAX);
}
//调用JNI方法
native_set(key, val);
}
Java的方法中调用的是native对应的get和set方法
二、framworks层JNI接口
frameworks/base/core/jni/android_os_SystemProperties.cpp
2.1 方法映射表
static 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 },
};
根据方法映射表,可以看到native_get和native_set对应着的方法实现。
2.2 native_get和native_set的实现
//native_get对应SystemProperties_getS
static jstring SystemProperties_getS(JNIEnv *env, jobject clazz,
jstring keyJ)
{
return SystemProperties_getSS(env, clazz, keyJ, NULL);
}
//SystemProperties_getS实际调用了SystemProperties_getSS
static jstring SystemProperties_getSS(JNIEnv *env, jobject clazz, jstring keyJ, jstring defJ)
{
int len;
const char* key;
char buf[PROPERTY_VALUE_MAX];
jstring rvJ = NULL;
if (keyJ == NULL) {
jniThrowNullPointerException(env, "key must not be null.");
goto error;
}
//将jstring类型变成一个char *类型
key = env->GetStringUTFChars(keyJ, NULL);
//关键代码:调用property_get方法,返回的数据写入bug,在properties.c中实现
len = property_get(key, buf, "");
//做一些错误处理
if ((len <= 0) && (defJ != NULL)) {
rvJ = defJ;
} else if (len >= 0) {
rvJ = env->NewStringUTF(buf);
} else {
rvJ = env->NewStringUTF("");
}
//调用ReleaseStringUTFChars函数通知JVM这块内存已经不使用
env->ReleaseStringUTFChars(keyJ, key);
error:
return rvJ;
}
//native_set方法对应SystemProperties_set
static void SystemProperties_set(JNIEnv *env, jobject clazz, jstring keyJ, jstring valJ)
{
LOGD("SystemProperties_set,keyJ=%s,valJ=%s", keyJ, valJ);
int err;
const char* key;
const char* val;
if (keyJ == NULL) {
jniThrowNullPointerException(env, "key must not be null.");
return ;
}
//将jstring类型变成一个char *类型
key = env->GetStringUTFChars(keyJ, NULL);
if (valJ == NULL) {
val = ""; /* NULL pointer not allowed here */
} else {
val = env->GetStringUTFChars(valJ, NULL);
}
//关键代码:调用property_set,在properties.c中实现
err = property_set(key, val);
//调用ReleaseStringUTFChars函数通知JVM这块内存已经不使用
env->ReleaseStringUTFChars(keyJ, key);
//一些错误处理
if (valJ != NULL) {
env->ReleaseStringUTFChars(valJ, val);
}
if (err < 0) {
jniThrowException(env, "java/lang/RuntimeException",
"failed to set system property");
}
}
从上面的分析中可以看到,JNI接口的set和get方法已经流转到properties.c中
三、kernel lib库层请求接口
3.1 接口调用 properties.c
system/core/libcutils/properties.c
//get方法,参数:<key,buf,def_value>
int property_get(const char *key, char *value, const char *default_value)
{
int len;
//关键调用,位于bionic/libc/bionic/system_properties.c
len = __system_property_get(key, value);
if(len > 0) {
return len;
}
if(default_value) {
len = strlen(default_value);
memcpy(value, default_value, len + 1);
}
return len;
}
//set方法,参数<key,value>
int property_set(const char *key, const char *value)
{
ALOGV("property_set, key=%s,value=%s", key, value);
//关键调用,位于bionic/libc/bionic/system_properties.c
return __system_property_set(key, value);
}
3.1.1 相关定义
- 属性操作类型定义
system/core/include/cutils/properties.h
//定义操作类型
enum {
kSystemPropertyUnknown = 0,
kSystemPropertyGet,
kSystemPropertySet,
kSystemPropertyList
};
- key,value长度定义
system/core/include/cutils/properties.h
/* System properties are *small* name value pairs managed by the
** property service. If your data doesn't fit in the provided
** space it is not appropriate for a system property.
**
** WARNING: system/bionic/include/sys/system_properties.h also defines
** these, but with different names. (TODO: fix that)
*/
#define PROPERTY_KEY_MAX PROP_NAME_MAX
#define PROPERTY_VALUE_MAX PROP_VALUE_MAX
bionic/libc/include/sys/system_properties.h
#define PROP_NAME_MAX 32
#define PROP_VALUE_MAX 92
pthread_once:在多线程环境中,有些事仅需要执行一次。通常当初始化应用程序时,可以比较容易地将其放在main函数中。但当你写一个库时,就不能在main里面初始化了,你可以用静态初始化,但使用一次初始化(pthread_once)会比较容易些
3.2 发送请求消息Socket客户端 system_properties.c
bionic/libc/bionic/system_properties.c
//get方法,参数<key, buff>
int __system_property_get(const char *name, char *value)
{
//检查该key值是否已经存在
const prop_info *pi = __system_property_find(name);
if(pi != 0) {
//如果存在,调用__system_property_read,返回值存储在pi中
return __system_property_read(pi, 0, value);
} else {//不存在则返回0
value[0] = 0;
return 0;
}
}
//get的调用,参数<prop_info,key, buff>
int __system_property_read(const prop_info *pi, char *name, char *value)
{
unsigned serial, len;
if (__predict_false(compat_mode)) {
return __system_property_read_compat(pi, name, value);
}
for(;;) {
serial = pi->serial;
while(SERIAL_DIRTY(serial)) {
__futex_wait((volatile void *)&pi->serial, serial, 0);
serial = pi->serial;
}
len = SERIAL_VALUE_LEN(serial);
memcpy(value, pi->value, len + 1);
ANDROID_MEMBAR_FULL();
if(serial == pi->serial) {
if(name != 0) {
strcpy(name, pi->name);
}
return len;
}
}
}
//set方法
int __system_property_set(const char *key, const char *value)
{
printf("__system_property_set--bianjb,key=%s,value=%s", key, value);
int err;
//prop_msg为要发送给服务端的消息句柄
prop_msg msg;
if(key == 0) return -1;
if(value == 0) value = "";
//判断key,value长度是否合法
if(strlen(key) >= PROP_NAME_MAX) return -1;
if(strlen(value) >= PROP_VALUE_MAX) return -1;
memset(&msg, 0, sizeof msg);
//设置Prop操作类型
msg.cmd = PROP_MSG_SETPROP;
//设置消息name字段
strlcpy(msg.name, key, sizeof msg.name);
//设置消息value字段
strlcpy(msg.value, value, sizeof msg.value);
//发送消息
err = send_prop_msg(&msg);
if(err < 0) {
return err;
}
return 0;
}
后面就是property_service接收到消息后的处理了,后面会继续更新。