Android 属性系统设计分析


前面已经讲过 " Android 属性系统 Property service 设定分析 " ,请参考


这篇博文主要讲解其属性系统的设计原理与思想方法,前一篇是实践,这一篇是理论,本质性原理。

首先看下整个属性系统结构图:



属性读取进程(property consumer)把这块共享内存映射到自己的进程空间,然后直接读取它。属性设置进程(property setter)也加载这块共享到他的进程空间,但是他不能直接写这块共享内存。当他需要增加或者修改属性的时候,通过Unix Socket发生属性给Property service,Property service将代表设置进程写入共享内存和属性文件。


1、属性服务初始化:

main @ /system/core/init 调用 property_init();

void property_init(void)
{
init_property_area();

// 加载默认 default.prop 文件
load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT);
}


属性服务代码: /system/core/init/property_service.c

static int init_property_area(void)

{

// 1、 创建一块用于存储属性的存储区域,其实就是一块匿名内存空间

if(init_workspace(&pa_workspace, PA_SIZE))

return -1;


fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC);


pa_info_array = (void*) (((char*) pa_workspace.data) + PA_INFO_START);


pa = pa_workspace.data;
memset(pa, 0, PA_SIZE);
pa->magic = PROP_AREA_MAGIC;
pa->version = PROP_AREA_VERSION;

// 这是由 bionic libc 库定义,大有来头哟,也是其它进程能够访问属性系统的关键所在

/* plug into the lib property services */

__system_property_area__ = pa;

}


以上代码建立的共享内存布局如下:



2、Property区域共享问题

Property service运行于init进程中,这里创建一块共享内存空间,但android系统希望其它进程也能够读取到这里内存中的内容,这里如何做到的呢?

A、属性系统内存区域建立于共享内存上,跨进程可以使用。由init_workspace()函数完成
B、利用linux的环境变量传递参数,这里传递 fd 及 size
service_start @ /system/core/init
void service_start(struct service *svc, const char *dynamic_args)

{

// 新的进程创建

pid = fork();

if (pid == 0) {

...
get_property_workspace(&fd, &sz);
// 注意这里哟,不同的进程需要使用必须首先dup(fd)值,最开始的 fd = 4 ,size =32768
sprintf(tmp, "%d,%d", dup(fd), sz);

// 注意这个环境变量: "ANDROID_PROPERTY_WORKSPACE" 后面会使用到
add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);

}


这里就是获取创建空间内存空间时的 fd 及 size 参数值
void get_property_workspace(int *fd, int *sz)
{
*fd = pa_workspace.fd;
*sz = pa_workspace.size;
}


C、利用 gcc 的 Contructor 属性
/* We flag the __libc_preinit function as a constructor to ensure
* that its address is listed in libc.so's .init_array section.
* This ensures that the function is called by the dynamic linker
* as soon as the shared library is loaded.
*/
void __attribute__((constructor)) __libc_prenit(void);

每个进程启动时都需要加载 bionic libc 库,那么这个函数将会一定自动执行,而这里将完成将属性共享内存空间映射到本地进程的内存空间。

__libc_prenit @ /bionic/libc/bionic/libc_init_dynamic.c

void __libc_prenit(void)
{
__libc_init_common(elfdata);
}
-->
void __libc_init_common(uintptr_t *elfdata)

{

/* setup system properties - requires environment */

__system_properties_init();

}


ok,现在看看我们重点关注的函数:

__system_properties_init @ /bionic/libc/bionic/system_properties.c


int __system_properties_init(void){prop_area *pa;int s, fd;unsigned sz;char *env;if(__system_property_area__ != ((void*) &dummy_props)) {return 0;}// 1、这里利用init进程中设定的环境变量 "ANDROID_PROPERTY_WORKSPACE"获取fd及size值   env = getenv("ANDROID_PROPERTY_WORKSPACE");if (!env) {return -1;}fd = atoi(env);env = strchr(env, ',');if (!env) {return -1;}sz = atoi(env + 1);// 本地进程映射属性内存空间,如此本地进程就可以使用这块共享内存,只能读取(PROT_READ)pa = mmap(0, sz, PROT_READ, MAP_SHARED, fd, 0);if(pa == MAP_FAILED) {return -1;}if((pa->magic != PROP_AREA_MAGIC) || (pa->version != PROP_AREA_VERSION)) {munmap(pa, sz);return -1;}// ok, __system_property_area__ 指向共享内存首地址__system_property_area__ = pa;return 0;}

可以在__system_properties_init 函数加打印 env 值,发现有新的进程加载bionic libc时,其值依次为:

__system_properties_initenv = 4,32768

__system_properties_initenv = 5,32768

__system_properties_initenv = 6,32768

__system_properties_initenv = 7,32768

__system_properties_initenv = 8,32768

__system_properties_initenv = 9,32768

因为在 init 进程中每次更新环境变量,dup(fd)值所以发生变化。


3、Property service 接收设置请求,利用socket请求,前面已经讲过就不复述了。


4、Property 属性系统使用
Native代码主要接口:
/system/core/libcutils/properties.c
int property_get(const char *key, char *value, const char *default_value);
int property_set(const char *key, const char *value);
int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie);


JAVA代码主要接口,存在两种访问方式:

libcore下面的System.java

System.getProperty(String prop,String defaultValue);
SystemsetProperty(String prop, String value);

/**
* Internal class holding the System properties. Needed by the Dalvik VM for the
* two native methods. Must not be a local class, since we don't have a System
* instance.
*/
class SystemProperties extends Properties {
// Dummy, just to make the compiler happy.

native void preInit();

native void postInit();
}

libcore下面的Properties.java
public class Properties extends Hashtable<Object, Object>

注意:这层属性操作的接口利用JVM中hash表来维护Java的属性

另处一种方式就是 通过framworks下面的 SystemProperties.java 利用jni操作属性系统
getXXX 及 set 函数

更多相关文章

  1. Android安全机制介绍
  2. Android面试系列文章2018之Android部分之动画机制篇
  3. android Kotlin 委托
  4. Android中native进程内存泄露的调试技巧
  5. Android(安卓)内存管理机制
  6. Android内存管理机制
  7. Android(安卓)匿名共享内存C接口分析
  8. Android多进程app中Application回调onCreate()方法被执行多次分
  9. Android(安卓)Button及TextView动态变换颜色

随机推荐

  1. Android View滑动
  2. android开启闪光灯
  3. 安卓课程二十二 ImageView的基本用法
  4. 升级到Android 10和gradle升级
  5. Android -- 重写android返回键
  6. Android http POST
  7. Android(安卓)8.1去除锁屏(MTK 平台)
  8. 我的Android进阶之旅------>Android电话
  9. Android(Gingerbread) Sensor Framework
  10. Android UI设计模式