Android4.4属性配置SystemProperties使用笔记

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 相关定义

  1. 属性操作类型定义
    system/core/include/cutils/properties.h
//定义操作类型
enum {
    kSystemPropertyUnknown = 0,
    kSystemPropertyGet,
    kSystemPropertySet,
    kSystemPropertyList
};
  1. 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接收到消息后的处理了,后面会继续更新。

©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值