android属性系统--应用程序get和set

前面一篇主要分析了属性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进程,具体由其进行属性的设置。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值