分享

Android系统属性set/get详解

 开花结果 2023-02-13 发布于北京

设置系统属性

上一篇文章提到,设置系统属性调用 SystemProperties.set("key", "value"); 即可。那么就从这个方法开始。

framework/base/core/java/android/os/SystemProperties.java

这里只是校验一下 key 和 value 的长度是否超过 31 和 91, 然后调用 native_set

framework/base/core/jni/android_os_SystemProperties.cpp

android_os_SystemProperties.cpp 中显示对 key 和 value 判空然后由 jstring 转化为 char*,最后调用 property_set。这个 property_set 是哪里来的呢?在 android_os_SystemProperties.cpp 的顶部我们看到上篇提到的 #include "cutils/properties.h" 原来 Java 层其实没什么实际的动作,最后还是调用和 native 层提供的方法。

system/core/cutils/properties.c

大致流程图下图:

通过上面的源码,我们可以看到:

  1. Java层只是做了简单的判断 key 和 value 的长度,以及 value 是否为空,然后通过 JNI 调用 native 的方法

  2. native 层也进行了是否为空和长度判断,然后封装了一个 prop_msg 并通过 socket 发送给 init 进程

对于属性设置的分析暂时就到这里,下一篇文章会分析系统属性的初始化,里面会涉及到 init 进程收到 prop_msg 具体会如何处理。

获取系统属性

不同于 set 方法只有一个,有好几个 get 方法,不过几个方法最终的实现都一样,这里我们以 getBoolean 为例:framework/base/core/java/android/os/SystemProperties.java

校验长度之后调用到 JNI 层中的 SystemProperties_get_boolean

framework/base/core/jni/android_os_SystemProperties.cpp

Java 层的各个 get 方法,在 JNI 对应的方法中统一掉了用 property_get 方法,然后对返回值进行处理,转换成 boolean,int,long..
native 层的各个方法,同样也是调用了 property_get,然后对返回值进行转换。

这里需要注意的是 property_get 方法返回的是 get 到的 value 的长度,真正的 value 是通过 property_get 的第二个参数得到的。

system/core/cutils/properties.c

bionic/libc/system_properties.cpp

查找共享内存

读取属性值

熟悉设置大概流程如下:

  1. 虽然 Java 层和 native 层都提供了多个 get 方法,但是最终实现都是一个(property_get),其他方法都是对该方法的返回值进行了转换

  2. 同 set 一样 Javac 层没做什么实际的操作,也是通过 JNI 调用到 native 方法

  3. native 层直接从共享内存中读取属性

虽然 set 和 get 方法介绍完了,但是感觉还是一脸懵逼。有很多疑问,
set 的时候为什么设置的时候要通过 socket 设置属性?
init 进程 收到 prop_msg 后又做了什么?
get 的时候为什么可以可以通过共享内存获取?

不急,我们先看下属性系统的框架,如下图:

光看图有点意犹未尽,先大概介绍一下就当预告了,下篇文章详细看代码。。。

  • 三个进程

    • consumer 进程将共享内存加载到自己的虚拟地址空间,并直接访问这些属性

    • setter 进程同样将共享内存加载到自己的虚拟地址空间,但是不能写内存。当需要增加或者修改系统属性时,它将该属性通过 unix domain socket 发送至 property 服务。

    • property 服务运行在 init 进程中,init 进程首先创建一个共享内存区域,并保存一个指向该区域的描述符 fd 。init 进程将该区域通过使用 MAP_SHARED 标志的 mmap 映射至自己的虚拟地址空间,这样,对于任何进程该区域的更新都是可见的。fd 和区域大小被存储在一个名为 ANDROID_PROPERTY_WORKSPACE 的变量中。任何其他进程都可以通过这个变量来获得 fd 和尺寸,这样就可以 mmap 这个区域到自己的虚拟地址空间中。

  • 永久属性文件
    系统初始化时,从永久文件中加载属性记录,并将它们保存到共享内存中。这些文件除了所有者,其他用户都没有可写权限

  • 共享内存区域
    所有进程都可以直接读取这块区域,但是只有 init 进程可以修改。结构如下图

property_get_bool 获取系统属性并强制转为bool

int8_t property_get_bool(const char *key, int8_t default_value);

根据键key所设置的值来判定返回一个bool值,若未对键key设置值,则返回默认值default_value。

若key所设置的值为以下值时,函数返回true:

"1", "true", "y", "yes", "on"

若key所设置的值为以下值时,函数返回false:

"0", "false", "n", "no", "off"

若是值为" off",其中带有一个空格,则为非false。

若是键key没有设置值,值为NULL或bool转换失败,则返回默认值default_value。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多