Android 属性系统设计分析
2016-04-09 15:37
666 查看
http://blog.csdn.net/andyhuabing/article/details/7406930
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
[cpp] view
plain copy
print?
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_init env = 4,32768
__system_properties_init env = 5,32768
__system_properties_init env = 6,32768
__system_properties_init env = 7,32768
__system_properties_init env = 8,32768
__system_properties_init env = 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 函数
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
[cpp] view
plain copy
print?
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_init env = 4,32768
__system_properties_init env = 5,32768
__system_properties_init env = 6,32768
__system_properties_init env = 7,32768
__system_properties_init env = 8,32768
__system_properties_init env = 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 函数
相关文章推荐
- Android 属性系统 Property service 设定分析
- 源码分析-Android中的消息机制详解
- android2.3 --- Service Manager分析
- Android右滑销毁Activity
- Android 播放音频文件
- Android Studio for Mac Install PlantUML plugin
- Android - 动态库双向依赖解决方法
- Android---NDK编译静态库失败
- Android学习--后台线程之Looper、Handler、HandlerThread
- Android -- Parcelable 序列化操作数据(上篇)
- Android2.3 MediaPlayer系统祥解系列(概述)
- Android学习基本索引(四)——记录,没事自己看
- Android从无知到有知——NO.3
- Android 日志系统logcat内核代码分析
- Android系统开发中LOG的输出与使用
- Android之利用正则表达式校验邮箱、手机号、密码、身份证号码等
- Android——getPreferences()、getSharedPreferences()和getDefaultSharedPreferences()区别
- Android 中文件类型与MIME的匹配表
- Android SDK下载技巧
- Android获取当前连接的wifi名称