android属性系统--应用程序get和set
16lz
2021-01-26
前面一篇主要分析了属性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进程,具体由其进行属性的设置。
更多相关文章
- [React Native Android(安卓)安利系列]样式与布局的书写
- Android(安卓)获取调用接口的包名
- android source code的获取及make
- 第十三篇 Android(安卓)系统电话管理机制与架构二
- android中fragment与activity之间通信
- Android获取系统播放音乐信息
- windows通过git获取 android 源代码
- android获取网络图片的用法 BitmapFactory.decodeByteArray 返回
- Android动画资源(三)——插值器