前面一篇主要分析了属性service端的初始化和处理过程,当一个应用程序要获取或者设置属性时,需要怎么去操作呢

获取属性可以通过调用property_get接口来完成

const char* property_get(const char *name){    prop_info *pi;    if(strlen(name) >= PROP_NAME_MAX) return 0;    pi = (prop_info*) __system_property_find(name);    if(pi != 0) {        return pi->value;    } else {        return 0;    }}

我们可以看到,其也是通过__system_property_find函数查找到该属性,然后返回其value值,但是,我们应该知道这个跟init进程不是同一个进程,而他又是怎么获取到在init进程中设置的属性值呢, 这就是通过前面的共享内存

bionic/libc/bionic/libc_init_dynamic.c文件中我们可以看到有 这样一句

/* 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_preinit(void)

__attribute__((constructor))表示这段代码将在main函数前调用,具体可以参考 http://blog.csdn.net/polisan/article/details/5031142

我们再看一下__libc_preinit函数

void __libc_preinit(void){    /* Read the ELF data pointer form a special slot of the     * TLS area, then call __libc_init_common with it.     *     * Note that:     * - we clear the slot so no other initializer sees its value.     * - __libc_init_common() will change the TLS area so the old one     *   won't be accessible anyway.     */    void**      tls_area = (void**)__get_tls();    unsigned*   elfdata   = tls_area[TLS_SLOT_BIONIC_PREINIT];    tls_area[TLS_SLOT_BIONIC_PREINIT] = NULL;    __libc_init_common(elfdata);    /* Setup malloc routines accordingly to the environment.     * Requires system properties     */    extern void malloc_debug_init(void);    malloc_debug_init();}

继续跟踪__libc_init_common

void __libc_init_common(uintptr_t *elfdata){    int     argc = *elfdata;    char**  argv = (char**)(elfdata + 1);    char**  envp = argv + argc + 1;    pthread_attr_t             thread_attr;    static pthread_internal_t  thread;    static void*               tls_area[BIONIC_TLS_SLOTS];    /* setup pthread runtime and maint thread descriptor */    unsigned stacktop = (__get_sp() & ~(PAGE_SIZE - 1)) + PAGE_SIZE;    unsigned stacksize = 128 * 1024;    unsigned stackbottom = stacktop - stacksize;    pthread_attr_init(&thread_attr);    pthread_attr_setstack(&thread_attr, (void*)stackbottom, stacksize);    _init_thread(&thread, gettid(), &thread_attr, (void*)stackbottom);    __init_tls(tls_area, &thread);    /* clear errno - requires TLS area */    errno = 0;    /* set program name */    __progname = argv[0] ? argv[0] : "<unknown>";    /* setup environment pointer */    environ = envp;    /* setup system properties - requires environment */    __system_properties_init();}
终于看到了__system_properties_init

int __system_properties_init(void){    prop_area *pa;    int s, fd;    unsigned sz;    char *env;    if(__system_property_area__ != ((void*) &dummy_props)) {        return 0;    }    env = getenv("ANDROID_PROPERTY_WORKSPACE");//获取环境变量值    if (!env) {        return -1;    }    fd = atoi(env);//获取fd    env = strchr(env, ',');    if (!env) {        return -1;    }    sz = atoi(env + 1);//获取size        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;    }    __system_property_area__ = pa;    return 0;}
这里从环境变量ANDROID_PROPERTY_WORKSPACE中读取共享内存的大小和fd,并把相关的值保存在__system_property_area__中,那么这个ANDROID_PROPERTY_WORKSPACE是在哪设置的 呢,我们再看一下init.c中的service_start
void service_start(struct service *svc, const char *dynamic_args){    struct stat s;    pid_t pid;    int needs_console;    ......    if (properties_inited()) {            get_property_workspace(&fd, &sz);            sprintf(tmp, "%d,%d", dup(fd), sz);            add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);        }    ......}
在启动一个service的时候,首先会判断 property_area_inited的值,如里 不为0,则调用get_property_workspace获取fd和映射的内存大小,接着调用add_environment设置ANDROID_PROPERTY_WORKSPACE的值。 这样,当我们启动一个应用程序的时候就可以获取 ANDROID_PROPERTY_WORKSPACE环境变量的值,从而实现共享了。

这样,property_get就可以很轻松的获取到我们前面设置的属性值了

2、property_set

int property_set(const char *key, const char *value){    prop_msg msg;    unsigned resp;    if(key == 0) return -1;    if(value == 0) value = "";        if(strlen(key) >= PROP_NAME_MAX) return -1;    if(strlen(value) >= PROP_VALUE_MAX) return -1;        msg.cmd = PROP_MSG_SETPROP;    strcpy((char*) msg.name, key);    strcpy((char*) msg.value, value);    return send_prop_msg(&msg);}
这里只是简单的调用send_prop_msg发送PROP_MSG_SETPROP消息。

static int send_prop_msg(prop_msg *msg){    int s;    int r;        s = socket_local_client(PROP_SERVICE_NAME,                             ANDROID_SOCKET_NAMESPACE_RESERVED,                            SOCK_STREAM);    if(s < 0) return -1;        while((r = send(s, msg, sizeof(prop_msg), 0)) < 0) {        if((errno == EINTR) || (errno == EAGAIN)) continue;        break;    }    if(r == sizeof(prop_msg)) {        r = 0;    } else {        r = -1;    }    close(s);    return r;}

建立一个到PROP_SERVICE_NAME的sock通信,然后把消息发到init进程,具体由其进行属性的设置。


更多相关文章

  1. [React Native Android(安卓)安利系列]样式与布局的书写
  2. Android(安卓)获取调用接口的包名
  3. android source code的获取及make
  4. 第十三篇 Android(安卓)系统电话管理机制与架构二
  5. android中fragment与activity之间通信
  6. Android获取系统播放音乐信息
  7. windows通过git获取 android 源代码
  8. android获取网络图片的用法 BitmapFactory.decodeByteArray 返回
  9. Android动画资源(三)——插值器

随机推荐

  1. C语言怎么输入十个数输出最大值
  2. %lf在c语言中表示什么
  3. c程序编译后生成什么文件
  4. 在C语言中,要求参加运算的数必须是整数的
  5. c语言goto语句用法
  6. c语言中#define的用法
  7. c语言逻辑运算符有哪些
  8. c语言源程序经过编译后,生成文件的后缀是
  9. c语言九九乘法表代码如何写
  10. c语言结构化程序设计的三种基本结构是什