Android4.4属性系统-属性获取

简介: 笔记

一、Android4.4属性系统系列文章


Android4.4属性系统-初始化

Android4.4属性系统-系统服务

Android4.4属性系统-内存空间共享

Android4.4属性系统-属性获取

Android4.4属性系统-属性设置

Android4.4-属性的使用总结


二、写在前面-如何阅读本系列文章


本系列文章大部分是对源码的解析和注释,所以读起来枯燥无味,并且杂乱,这是阅读系统源码无法避免的,如果你有条件,可以点击下载Android4.4源码,阅读源码可以使用eclise,AndroidStudio,vim等。

文章的章节安卓是按照代码模块区分的,例如init进程代码,libcutils代码是按章节来区分,但不同模块的代码之间是有关联的,阅读时需要经常跳转,通过搜索功能进行页内搜索即可


三、安卓属性获取


在 Android 应用程序开发中,可以通过 android.os.Build 类来访问一些属性信息,如设备品牌,设备名称,CPU 信息等。我们以访问 Build.java相关接口 来分析 Android 系统中是如何获取属性信息的。


3.1 frameworks接口

3.1.1 Build.java

源码路径frameworks/base/core/java/android/os/Build.java

以下是截取了一小段代码

/** Value used for when a build property is unknown. */
public static final String UNKNOWN = "unknown";
/** Either a changelist number, or a label like "M4-rc20". */
public static final String ID = getString("ro.build.id");
/** A build ID string meant for displaying to the user */
public static final String DISPLAY = getString("ro.build.display.id");
/** The name of the overall product. */
public static final String PRODUCT = getString("ro.product.name");
/** The name of the industrial design. */
public static final String DEVICE = getString("ro.product.device");
/** The name of the underlying board, like "goldfish". */
public static final String BOARD = getString("ro.product.board");
private static String getString(String property) {
    return SystemProperties.get(property, UNKNOWN);
}
private static long getLong(String property) {
    try {
        return Long.parseLong(SystemProperties.get(property));
    } catch (NumberFormatException e) {
        return -1;
    }
}

可以看到Build.java中定义常量字段在构造函数之前确定,调用的是getString()方法,我们以Build.PRODUCT为例,进行探究。

代码流转到SystemProperties.java


3.1.2 SystemProperties.java

源码 路径:frameworks/base/core/java/android/os/SystemProperties.java

private static native String native_get(String key);  //调用的naveti方法,key="ro.product.name"
private static native String native_get(String key, String def);
private static native int native_get_int(String key, int def);
private static native long native_get_long(String key, long def);
private static native boolean native_get_boolean(String key, boolean def);
private static native void native_set(String key, String def);
private static native void native_add_change_callback();
/**
 * 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
 */
//key="ro.product.name"
public static String get(String key) {
    if (key.length() > PROP_NAME_MAX) {
        throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
    }
    return native_get(key);
}

一般来说调用 Native 函数,需要在 static 块中加载对应的库,即调用 System.loadLibrary,但是在 SystemProperties 类中并没有显示的加载对应的库。原来在 Zygote 启动过程中会调用startReg 来注册 JNI 函数,native_get 这个 JNI 函数就是在此时注册的。关于注册过程可以简单分析如下。


3.1.3 native函数注册过程

源码路径frameworks/base/cmds/app_process/app_main.cpp

int main(int argc, char* const argv[])
{
    bool zygote = false;  //是否是zygote进程
    ...
    while (i < argc) {
        ...
        } else if (strcmp(arg, "--zygote") == 0) {
            zygote = true;  //是zygote进程
            niceName = "zygote";
        } else if (strcmp(arg, "--start-system-server") == 0) {
         ...
    }
   if (zygote) {  //启动Zygote
       runtime.start("com.android.internal.os.ZygoteInit",
               startSystemServer ? "start-system-server" : "");
   } else if (className) {
      ...
    }
}

源码路径frameworks/base/core/jni/AndroidRuntime.cpp

//注册函数数组
static const RegJNIRec gRegJNI[] = {
    ....
    REG_JNI(register_android_os_SystemProperties),  //注册函数
    ....
}
void AndroidRuntime::start(const char* className, const char* options)
{
     ...
   /*
    * Register android functions.
    * startReg 完成相关 Native 函数的注册,该函数最终调用 register_jni_procs 完成注册过程
    */
   if (startReg(env) < 0) {
       ALOGE("Unable to register all android natives\n");
       return;
   }
    ...
}
/*
 * Register android native functions with the VM.
 */
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{   
    ...
    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
        env->PopLocalFrame(NULL);
     ...      
}
/*register_jni_procs 会遍历传入的 RegJNIRec 数组并调用相应的函数进行注册,这个数组定义在
*AndroidRuntime.cpp 中名为 gRegJNI,其中包括了 register_android_os_SystemProperties,这个
*函数定义在/frameworks/base/core/jni/android_os_SystemProperties.cpp 中
*/
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
{
    for (size_t i = 0; i < count; i++) {
        if (array[i].mProc(env) < 0) {
            return -1;
        }
    }
    return 0;
}

3.2 JNI接口

源码 路径frameworks/base/core/jni/android_os_SystemProperties.cpp

JNI代码中,有方法映射表,native_get映射为SystemProperties_getS方法

#include "cutils/properties.h"
//方法映射表
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 },
};
//keyJ="ro.product.name"
//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;
}   
/*JNI注册函数,通过 AndroidRuntime::registerNativeMethods 注册 method_table 数组参数中定义的 Native 函数。
*关于 registerNativeMethods,有兴趣的可以继续分析,此处就忽略了,后续会另外开篇进行分析
*/
int register_android_os_SystemProperties(JNIEnv *env)
{
    return AndroidRuntime::registerNativeMethods(
        env, "android/os/SystemProperties",
        method_table, NELEM(method_table));
}

3.3 libc库层

3.3.1 内核c库层

源码路径system/core/libcutils/properties.c

#include <cutils/properties.h>
//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;
}

3.3.2 bionic库层

源码路径bionic/libc/bionic/system_properties.c

该函数通过__system_property_find 函数在系统属性内存区域查询是否存在 name 参数指定的属性,如果查询到则会通过__system_property_read 读取属性信息。关于__system_property_find函数,前文已经分析过了。__system_property_read 通过获取的内存地址,从内存中读取属性信息。

//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);
    }
    //prop_info 中的 serial,其高8 位表示该 prop_info 中 name 的长度,而低 24 位表示该 prop_info 被更新的次数
    for(;;) {
        serial = pi->serial;  
        while(SERIAL_DIRTY(serial)) {
            __futex_wait((volatile void *)&pi->serial, serial, 0);
            serial = pi->serial;
        }
        len = SERIAL_VALUE_LEN(serial);  //获取prop的name长度
        memcpy(value, pi->value, len + 1);  //获取value值
        ANDROID_MEMBAR_FULL();
        if(serial == pi->serial) {
            if(name != 0) {
                strcpy(name, pi->name);
            }
            return len;
        }
    }
}


四、放图


18.png

五、参考


Android属性系统

Linux 内存映射函数 mmap

trie-特里结构

Linux 内存映射函数 mmap()函数详解

目录
相关文章
|
2月前
|
Android开发
基于android-11.0.0_r39,系统应用的手动签名方法和过程
本文介绍了基于Android 11.0.0_r39版本进行系统应用手动签名的方法和解决签名过程中遇到的错误,包括处理`no conscrypt_openjdk_jni-linux-x86_64`和`RegisterNatives failed`的问题。
88 2
|
2月前
|
JavaScript 前端开发 Java
[Android][Framework]系统jar包,sdk的制作及引用
[Android][Framework]系统jar包,sdk的制作及引用
43 0
|
3月前
|
搜索推荐 Android开发 iOS开发
探索安卓与iOS系统的用户界面设计哲学
现代移动操作系统的设计哲学不仅仅是技术的表现,更是用户体验与功能实现的结合。本文将深入分析安卓与iOS两大主流系统在用户界面设计方面的差异与共通之处,探讨它们背后的思维模式及其对用户体验的影响。 【7月更文挑战第11天】
|
8天前
|
监控 Android开发 iOS开发
深入探索安卓与iOS的系统架构差异:理解两大移动平台的技术根基在移动技术日新月异的今天,安卓和iOS作为市场上最为流行的两个操作系统,各自拥有独特的技术特性和庞大的用户基础。本文将深入探讨这两个平台的系统架构差异,揭示它们如何支撑起各自的生态系统,并影响着全球数亿用户的使用体验。
本文通过对比分析安卓和iOS的系统架构,揭示了这两个平台在设计理念、安全性、用户体验和技术生态上的根本区别。不同于常规的技术综述,本文以深入浅出的方式,带领读者理解这些差异是如何影响应用开发、用户选择和市场趋势的。通过梳理历史脉络和未来展望,本文旨在为开发者、用户以及行业分析师提供有价值的见解,帮助大家更好地把握移动技术发展的脉络。
|
5天前
|
Dart 开发工具 Android开发
在 Android 系统上搭建 Flutter 环境的具体步骤是什么?
在 Android 系统上搭建 Flutter 环境的具体步骤是什么?
|
28天前
|
Android开发 UED 开发者
Android经典实战之WindowManager和创建系统悬浮窗
本文详细介绍了Android系统服务`WindowManager`,包括其主要功能和工作原理,并提供了创建系统悬浮窗的完整步骤。通过示例代码,展示了如何添加权限、请求权限、实现悬浮窗口及最佳实践,帮助开发者轻松掌握悬浮窗开发技巧。
55 1
|
2月前
|
Java 物联网 Android开发
移动应用与系统:技术演进与未来展望探索安卓应用开发:从新手到专家的旅程
【8月更文挑战第28天】本文将深入探讨移动应用开发的技术演进、移动操作系统的发展历程以及未来的发展趋势。我们将通过实例和代码示例,展示如何利用最新的技术和工具来开发高效、可靠的移动应用。无论你是初学者还是经验丰富的开发者,这篇文章都将为你提供有价值的信息和见解。 【8月更文挑战第28天】在这个数字时代,掌握安卓应用的开发技能不仅是技术人员的追求,也成为了许多人实现创意和梦想的途径。本文将通过深入浅出的方式,带领读者从零基础开始,一步步走进安卓开发的奇妙世界。我们将探讨如何配置开发环境,理解安卓应用的核心组件,以及如何通过实际编码来构建一个功能完整的应用。无论你是编程新手还是希望提升自己的开发者
|
2月前
|
存储 安全 物联网
Android经典实战之跳转到系统设置页面或其他系统应用页面大全
本文首发于公众号“AntDream”,关注获取更多技巧。文章总结了Android开发中跳转至系统设置页面的方法,包括设备信息、Wi-Fi、显示与声音设置等,并涉及应用详情与电池优化页面。通过简单的Intent动作即可实现,需注意权限与版本兼容性。每日进步,尽在“AntDream”。
168 2
|
2月前
|
安全 Android开发 iOS开发
安卓与iOS的终极对决:哪个系统更适合你?
在智能手机的世界里,安卓和iOS两大操作系统如同两座巍峨的山峰,各自拥有庞大的用户群体。本文将深入浅出地探讨这两个系统的优缺点,并帮助你找到最适合自己的那一款。让我们一起揭开这场技术盛宴的序幕吧!
|
3月前
|
Android开发 Kotlin
kotlin开发安卓app,如何让布局自适应系统传统导航和全面屏导航
使用`navigationBarsPadding()`修饰符实现界面自适应,自动处理底部导航栏的内边距,再加上`.padding(bottom = 10.dp)`设定内容与屏幕底部的距离,以完成全面的布局适配。示例代码采用Kotlin。
102 15