本文简单介绍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接收到消息后的处理了,后面会继续更新。