init进程【3】——属性服务

来源:互联网 发布:雅思网络培训班 编辑:程序博客网 时间:2024/06/07 23:25

【转载自这里】:http://blog.csdn.net/zhgxhuaa


Android中的属性主要用来保存一些全局性的信息,这里可以理解为Android中的“注册表”。Android中的属性服务只针对系统开发者使用,并不对应用开发者开发,这通过SystemProperties是hide的可以看出。下面让我们一起来剖析属性服务。


初始化属性空间

在init进程启动一文中我们讲到,init的其中一个作用就是启动系统属性服务。在init进程的main()函数中有这样一句:

@system/core/init/init.c

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. property_init();//属性服务初始化  
property_init()的实现如下:

@system/core/init/property_service.c

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. void property_init(void)  
  2. {  
  3.     init_property_area();  
  4. }  
从字面意思来看init_property_area是用来初始化属性存储区域,让我们来看一下:

@system/core/init/property_service.c

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. static int init_property_area(void)  
  2. {  
  3.     if (property_area_inited)//属性区域已初始化则直接返回,不再初始化  
  4.         return -1;  
  5.   
  6.     if(__system_property_area_init())//通过mmap创建共享内存  
  7.         return -1;  
  8.   
  9.     if(init_workspace(&pa_workspace, 0))//初始化pa_workspace  
  10.         return -1;  
  11.   
  12.     fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC);  
  13.   
  14.     property_area_inited = 1;  
  15.     return 0;  
  16. }  

通过上面的代码我们可以知道,属性服务是创建在共享内存上的,通过共享内存实现跨进程的访问。那共享内存是如何创建的呢?来看一下__system_property_area_init的实现:

@/bionic/libc/bionic/system_properties.c

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. int __system_property_area_init()  
  2. {  
  3.     return map_prop_area_rw();  
  4. }  
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. static int map_prop_area_rw()  
  2. {  
  3.     prop_area *pa;  
  4.     int fd;  
  5.     int ret;  
  6.   
  7.     /* dev is a tmpfs that we can use to carve a shared workspace 
  8.      * out of, so let's do that... 
  9.      */  
  10.     fd = open(property_filename, O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC |  
  11.             O_EXCL, 0444);//打开property_filename文件,即:/dev/__properties__  
  12.     if (fd < 0) {  
  13.         if (errno == EACCES) {  
  14.             /* for consistency with the case where the process has already 
  15.              * mapped the page in and segfaults when trying to write to it 
  16.              */  
  17.             abort();  
  18.         }  
  19.         return -1;  
  20.     }  
  21.   
  22.     ret = fcntl(fd, F_SETFD, FD_CLOEXEC);//这里设置为FD_CLOEXEC表示当程序执行exec函数时本fd将被系统自动关闭,表示不传递给exec创建的新进程  
  23.     if (ret < 0)  
  24.         goto out;  
  25.   
  26.     if (ftruncate(fd, PA_SIZE) < 0)//更改fd指向文件的大小为PA_SIZE(128 * 1024)大小  
  27.         goto out;  
  28.   
  29.     pa_size = PA_SIZE;//设置属性空间的大小为PA_SIZE(128 * 1024)  
  30.     pa_data_size = pa_size - sizeof(prop_area);//属性空间中可以用来保存属性的区域的大小,prop_area用来保存属性空间自身的一些信息  
  31.     compat_mode = false;  
  32.   
  33.     pa = mmap(NULL, pa_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);//映射属性文件到进程  
  34.     if(pa == MAP_FAILED)  
  35.         goto out;  
  36.   
  37.     memset(pa, 0, pa_size);//初始化属性区域  
  38.     pa->magic = PROP_AREA_MAGIC;  
  39.     pa->version = PROP_AREA_VERSION;  
  40.     /* reserve root node */  
  41.     pa->bytes_used = sizeof(prop_bt);  
  42.   
  43.     /* plug into the lib property services */  
  44.     __system_property_area__ = pa;  
  45.   
  46.     close(fd);  
  47.     return 0;  
  48.   
  49. out:  
  50.     close(fd);  
  51.     return -1;  
  52. }  

上面的内容比较简单,不过最后的赋值语句可是大有来头。_system_property_area_是bionic libc库中输出的一个变量,为什么这里要给她赋值呢?

原来,虽然属性区域是由init进程创建的,但是Android系统希望其他进程也能够读取这块内存的东西。为了做到这一点,它便做了一下两项工作:

  • 把属性区域创建在共享内存上,而共享内存是可以跨进程的。
  • 如何让其他进程知道这个共享内存呢?Android利用gcc的constructor属性,这个属性指明了一个_libc_prenit函数,当bionic libc库被加载时,将自动调用这个_libc_prenit,这个函数内部完成共享内存到本地进程的映射工作。(这一段说明转自:《深入理解Android:卷1》)

关于上面的内容来看下面的代码:

@/bionic/libc/bionic/libc_init_dynamic.cpp
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. // We flag the __libc_preinit function as a constructor to ensure  
  2. // that its address is listed in libc.so's .init_array section.  
  3. // This ensures that the function is called by the dynamic linker  
  4. // as soon as the shared library is loaded.  
  5. __attribute__((constructor)) static void __libc_preinit() {  
  6.   // Read the kernel argument block pointer from TLS.  
  7.   void* tls = const_cast<void*>(__get_tls());  
  8.   KernelArgumentBlock** args_slot = &reinterpret_cast<KernelArgumentBlock**>(tls)[TLS_SLOT_BIONIC_PREINIT];  
  9.   KernelArgumentBlock* args = *args_slot;  
  10.   
  11.   // Clear the slot so no other initializer sees its value.  
  12.   // __libc_init_common() will change the TLS area so the old one won't be accessible anyway.  
  13.   *args_slot = NULL;  
  14.   
  15.   __libc_init_common(*args);  
  16.   
  17.   // Hooks for the debug malloc and pthread libraries to let them know that we're starting up.  
  18.   pthread_debug_init();  
  19.   malloc_debug_init();  
  20. }  

@/bionic/libc/bionic/libc_init_common.cpp

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. void __libc_init_common(KernelArgumentBlock& args) {  
  2.   // Initialize various globals.  
  3.   environ = args.envp;  
  4.   errno = 0;  
  5.   __libc_auxv = args.auxv;  
  6.   __progname = args.argv[0] ? args.argv[0] : "<unknown>";  
  7.   __abort_message_ptr = args.abort_message_ptr;  
  8.   
  9.   // AT_RANDOM is a pointer to 16 bytes of randomness on the stack.  
  10.   __stack_chk_guard = *reinterpret_cast<uintptr_t*>(getauxval(AT_RANDOM));  
  11.   
  12.   // Get the main thread from TLS and add it to the thread list.  
  13.   pthread_internal_t* main_thread = __get_thread();  
  14.   main_thread->allocated_on_heap = false;  
  15.   _pthread_internal_add(main_thread);  
  16.   
  17.   __system_properties_init(); // Requires 'environ'.  
  18. }  
@/bionic/libc/bionic/system_properties.c

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. int __system_properties_init()  
  2. {  
  3.     return map_prop_area();  
  4. }  
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. static int map_prop_area()  
  2. {  
  3.     bool fromFile = true;  
  4.     int result = -1;  
  5.     int fd;  
  6.     int ret;  
  7.   
  8.     fd = open(property_filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);  
  9.     if (fd >= 0) {  
  10.         /* For old kernels that don't support O_CLOEXEC */  
  11.         ret = fcntl(fd, F_SETFD, FD_CLOEXEC);  
  12.         if (ret < 0)  
  13.             goto cleanup;  
  14.     }  
  15.   
  16.     if ((fd < 0) && (errno == ENOENT)) {  
  17.         /* 
  18.          * For backwards compatibility, if the file doesn't 
  19.          * exist, we use the environment to get the file descriptor. 
  20.          * For security reasons, we only use this backup if the kernel 
  21.          * returns ENOENT. We don't want to use the backup if the kernel 
  22.          * returns other errors such as ENOMEM or ENFILE, since it 
  23.          * might be possible for an external program to trigger this 
  24.          * condition. 
  25.          */  
  26.         fd = get_fd_from_env();  
  27.         fromFile = false;  
  28.     }  
  29.   
  30.     if (fd < 0) {  
  31.         return -1;  
  32.     }  
  33.   
  34.     struct stat fd_stat;  
  35.     if (fstat(fd, &fd_stat) < 0) {  
  36.         goto cleanup;  
  37.     }  
  38.   
  39.     if ((fd_stat.st_uid != 0)  
  40.             || (fd_stat.st_gid != 0)  
  41.             || ((fd_stat.st_mode & (S_IWGRP | S_IWOTH)) != 0)  
  42.             || (fd_stat.st_size < sizeof(prop_area)) ) {  
  43.         goto cleanup;  
  44.     }  
  45.   
  46.     pa_size = fd_stat.st_size;  
  47.     pa_data_size = pa_size - sizeof(prop_area);  
  48.     prop_area *pa = mmap(NULL, pa_size, PROT_READ, MAP_SHARED, fd, 0);  
  49.   
  50.     if (pa == MAP_FAILED) {  
  51.         goto cleanup;  
  52.     }  
  53.   
  54.     if((pa->magic != PROP_AREA_MAGIC) || (pa->version != PROP_AREA_VERSION &&  
  55.                 pa->version != PROP_AREA_VERSION_COMPAT)) {  
  56.         munmap(pa, pa_size);  
  57.         goto cleanup;  
  58.     }  
  59.   
  60.     if (pa->version == PROP_AREA_VERSION_COMPAT) {  
  61.         compat_mode = true;  
  62.     }  
  63.   
  64.     result = 0;  
  65.   
  66.     __system_property_area__ = pa;  
  67.   
  68. cleanup:  
  69.     if (fromFile) {  
  70.         close(fd);  
  71.     }  
  72.   
  73.     return result;  
  74. }  
对比上面map_prop_area_rw()和map_prop_area()这两个方法,我们可以发现他们在打开文件和进行映射时的不同。在map_prop_area_rw()中:
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. static int map_prop_area_rw()  
  2. {  
  3.     ......  
  4.   
  5.     fd = open(property_filename, O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC |  
  6.             O_EXCL, 0444);  
  7.       
  8.     ......  
  9.           
  10.     pa = mmap(NULL, pa_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);//映射属性文件到进程  
  11.   
  12.     ......  
  13. }  

在map_prop_area()中:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. static int map_prop_area()  
  2. {  
  3.     ......  
  4.   
  5.     fd = open(property_filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);  
  6.       
  7.     ......  
  8.       
  9.     prop_area *pa = mmap(NULL, pa_size, PROT_READ, MAP_SHARED, fd, 0);  
  10.   
  11.     ......  
  12. }  
map_prop_area_rw()是init进程初始化属性服务时调用到的;map_prop_area()则是其他进程通过bionic初始化时调用的。通过对比,也说明只有init进程才拥有属性的写权限,其他进程只能读。好了,到这里又引出来另外一个问题,其他进程要想设置属性,应该怎么做呢?

属性服务

启动属性服务

在init进程的main()中,我们可以看见如下语句:

@system/core/init/init.c

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. queue_builtin_action(property_service_init_action, "property_service_init");  

这句话的意思是启动action链表中的property服务:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. static int property_service_init_action(int nargs, char **args)  
  2. {  
  3.     /* read any property files on system or data and 
  4.      * fire up the property service.  This must happen 
  5.      * after the ro.foo properties are set above so 
  6.      * that /data/local.prop cannot interfere with them. 
  7.      */  
  8.     start_property_service();  
  9.     return 0;  
  10. }  
start_property_service()的实现如下:

@system/core/init/property_service.c

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. void start_property_service(void)  
  2. {  
  3.     int fd;  
  4.   
  5.     load_properties_from_file(PROP_PATH_SYSTEM_BUILD);  
  6.     load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);  
  7.     load_override_properties();  
  8.     /* Read persistent properties after all default values have been loaded. */  
  9.     load_persistent_properties();  
  10.   
  11.     fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0);  
  12.     if(fd < 0) return;  
  13.     fcntl(fd, F_SETFD, FD_CLOEXEC);  
  14.     fcntl(fd, F_SETFL, O_NONBLOCK);  
  15.   
  16.     listen(fd, 8);  
  17.     property_set_fd = fd;  
  18. }  
关于这段代码做一些说明:

在Android中定义了5个存储属性的文件,它们分别是:

@/bionic/libc/includes/sys/_system_properties.h

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. #define PROP_PATH_RAMDISK_DEFAULT  "/default.prop"  
  2. #define PROP_PATH_SYSTEM_BUILD     "/system/build.prop"  
  3. #define PROP_PATH_SYSTEM_DEFAULT   "/system/default.prop"  
  4. #define PROP_PATH_LOCAL_OVERRIDE   "/data/local.prop"  
  5. #define PROP_PATH_FACTORY          "/factory/factory.prop"  
load_persistent_properties()用来加载persist开头的属性文件,这些属性文件是需要保存到永久介质上的,这些属性文件存储在/data/property目录下,并且文件名必须以“psesist."开头,下面是我的手机上的persist属性文件:



在start_property_service()的最后创建了一个名为"property_service"的socket,启动监听,并将socket的句柄保存在property_set_fd中。


处理设置属性请求

接收属性设置请求的地方在init进程中:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. nr = poll(ufds, fd_count, timeout);  
  2. if (nr <= 0)  
  3.     continue;  
  4.   
  5. for (i = 0; i < fd_count; i++) {  
  6.     if (ufds[i].revents == POLLIN) {  
  7.         if (ufds[i].fd == get_property_set_fd())  
  8.             handle_property_set_fd();  
  9.         else if (ufds[i].fd == get_keychord_fd())  
  10.             handle_keychord();  
  11.         else if (ufds[i].fd == get_signal_fd())  
  12.             handle_signal();  
  13.     }  
  14. }  
可以看到,在init接收到其他进程设置属性的请求时,会调用handle_property_set_fd()函数进程处理:

@system/core/init/property_service.c

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. void handle_property_set_fd()  
  2. {  
  3.     prop_msg msg;  
  4.     int s;  
  5.     int r;  
  6.     int res;  
  7.     struct ucred cr;  
  8.     struct sockaddr_un addr;  
  9.     socklen_t addr_size = sizeof(addr);  
  10.     socklen_t cr_size = sizeof(cr);  
  11.     char * source_ctx = NULL;  
  12.   
  13.     if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {  
  14.         return;  
  15.     }  
  16.   
  17.     /* Check socket options here */  
  18.     if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {  
  19.         close(s);  
  20.         ERROR("Unable to receive socket options\n");  
  21.         return;  
  22.     }  
  23.   
  24.     r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), 0));  
  25.     if(r != sizeof(prop_msg)) {  
  26.         ERROR("sys_prop: mis-match msg size received: %d expected: %d errno: %d\n",  
  27.               r, sizeof(prop_msg), errno);  
  28.         close(s);  
  29.         return;  
  30.     }  
  31.   
  32.     switch(msg.cmd) {  
  33.     case PROP_MSG_SETPROP:  
  34.         msg.name[PROP_NAME_MAX-1] = 0;  
  35.         msg.value[PROP_VALUE_MAX-1] = 0;  
  36.   
  37.         if (!is_legal_property_name(msg.name, strlen(msg.name))) {  
  38.             ERROR("sys_prop: illegal property name. Got: \"%s\"\n", msg.name);  
  39.             close(s);  
  40.             return;  
  41.         }  
  42.   
  43.         getpeercon(s, &source_ctx);  
  44.   
  45.         if(memcmp(msg.name,"ctl.",4) == 0) {  
  46.             // Keep the old close-socket-early behavior when handling  
  47.             // ctl.* properties.  
  48.             close(s);  
  49.             if (check_control_perms(msg.value, cr.uid, cr.gid, source_ctx)) {  
  50.                 handle_control_message((char*) msg.name + 4, (char*) msg.value);  
  51.             } else {  
  52.                 ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n",  
  53.                         msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);  
  54.             }  
  55.         } else {  
  56.             if (check_perms(msg.name, cr.uid, cr.gid, source_ctx)) {  
  57.                 property_set((char*) msg.name, (char*) msg.value);  
  58.             } else {  
  59.                 ERROR("sys_prop: permission denied uid:%d  name:%s\n",  
  60.                       cr.uid, msg.name);  
  61.             }  
  62.   
  63.             // Note: bionic's property client code assumes that the  
  64.             // property server will not close the socket until *AFTER*  
  65.             // the property is written to memory.  
  66.             close(s);  
  67.         }  
  68.         freecon(source_ctx);  
  69.         break;  
  70.   
  71.     default:  
  72.         close(s);  
  73.         break;  
  74.     }  
  75. }  
从上面的代码可以看出在进行一系列检查和判断后,最后悔调用property_set()函数设置属性,其实现如下:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. int property_set(const char *name, const char *value)  
  2. {  
  3.     prop_info *pi;  
  4.     int ret;  
  5.   
  6.     size_t namelen = strlen(name);  
  7.     size_t valuelen = strlen(value);  
  8.   
  9.     if (!is_legal_property_name(name, namelen)) return -1;  
  10.     if (valuelen >= PROP_VALUE_MAX) return -1;  
  11.   
  12.     pi = (prop_info*) __system_property_find(name);  
  13.   
  14.     if(pi != 0) {  
  15.         /* ro.* properties may NEVER be modified once set */  
  16.         if(!strncmp(name, "ro.", 3)) return -1;  
  17.   
  18.         __system_property_update(pi, value, valuelen);  
  19.     } else {  
  20.         ret = __system_property_add(name, namelen, value, valuelen);  
  21.         if (ret < 0) {  
  22.             ERROR("Failed to set '%s'='%s'\n", name, value);  
  23.             return ret;  
  24.         }  
  25.     }  
  26.     /* If name starts with "net." treat as a DNS property. */  
  27.     if (strncmp("net.", name, strlen("net.")) == 0)  {  
  28.         if (strcmp("net.change", name) == 0) {  
  29.             return 0;  
  30.         }  
  31.        /* 
  32.         * The 'net.change' property is a special property used track when any 
  33.         * 'net.*' property name is updated. It is _ONLY_ updated here. Its value 
  34.         * contains the last updated 'net.*' property. 
  35.         */  
  36.         property_set("net.change", name);  
  37.     } else if (persistent_properties_loaded &&  
  38.             strncmp("persist.", name, strlen("persist.")) == 0) {  
  39.         /* 
  40.          * Don't write properties to disk until after we have read all default properties 
  41.          * to prevent them from being overwritten by default values. 
  42.          */  
  43.         write_persistent_property(name, value);  
  44.     } else if (strcmp("selinux.reload_policy", name) == 0 &&  
  45.                strcmp("1", value) == 0) {  
  46.         selinux_reload_policy();  
  47.     }  
  48.     property_changed(name, value);  
  49.     return 0;  
  50. }  

从上面的代码可以看出:首先会判断所设置属性的属性名和属性值是否超过限制,这个限制定义如下:

@bionic/libc/includes/sys/system _properties.h

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. #define PROP_NAME_MAX   32  
  2. #define PROP_VALUE_MAX  92  
可以看出属性名最长不能超过32个字符;属性值最长不能超过92个字符,到这里我们也可以根据之前map_prop_area_rw()中的信息推断出,系统总共可以支持多少个属性:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. pa_size = PA_SIZE;//设置属性空间的大小为PA_SIZE(128 * 1024)  
  2. pa_data_size = pa_size - sizeof(prop_area);//属性空间中可以用来保存属性的区域的大小,prop_area用来保存属性空间自身的一些信息  
  3. compat_mode = false;  
按照这里的推断,系统支持1000多个属性的样子。这里与之前比较老的Android版本有所不同,在老的Android版本中系统最多支持的属性个数为247个。

在判断文新添加属性的合法性以后接下来会判断该属性是否以存在,如果已存在则更新属性的值即可,如果不存在则增加新的属性。

然后还有剩下的一些其他判断,这里就不再赘述。到时最后一句property_changed()引起了我的注意:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. property_changed(name, value);  
看到这里,你有没有想起些什么?是的,init.rc中类似于下面这样的句子就是在这里通过property_changed()触发的。

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. on property:vold.decrypt=trigger_restart_min_framework  
  2.     class_start main  
  3.   
  4. on property:vold.decrypt=trigger_restart_framework  
  5.     class_start main  
  6.     class_start late_start  

OK,到这里属性服务相关的东东基本介绍完了。接下来简单介绍一下如何设置系统属性。


设置系统属性

C代码中属性的设置是由libcutils库提供的,代码如下:

@system/core/libutils/properties.c

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. int property_set(const char *key, const char *value)  
  2. {  
  3.     return __system_property_set(key, value);  
  4. }  

@/bionic/libc/bionic/system_property

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. int __system_property_set(const char *key, const char *value)  
  2. {  
  3.     int err;  
  4.     prop_msg msg;  
  5.   
  6.     if(key == 0) return -1;  
  7.     if(value == 0) value = "";  
  8.     if(strlen(key) >= PROP_NAME_MAX) return -1;  
  9.     if(strlen(value) >= PROP_VALUE_MAX) return -1;  
  10.   
  11.     memset(&msg, 0, sizeof msg);  
  12.     msg.cmd = PROP_MSG_SETPROP;  
  13.     strlcpy(msg.name, key, sizeof msg.name);  
  14.     strlcpy(msg.value, value, sizeof msg.value);  
  15.   
  16.     err = send_prop_msg(&msg);  
  17.     if(err < 0) {  
  18.         return err;  
  19.     }  
  20.   
  21.     return 0;  
  22. }  
注意这里的msg.cmd = PROP_MSG_SETPROP,send_prop_msg()的实现如下:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. static int send_prop_msg(prop_msg *msg)  
  2. {  
  3.     struct pollfd pollfds[1];  
  4.     struct sockaddr_un addr;  
  5.     socklen_t alen;  
  6.     size_t namelen;  
  7.     int s;  
  8.     int r;  
  9.     int result = -1;  
  10.   
  11.     s = socket(AF_LOCAL, SOCK_STREAM, 0);  
  12.     if(s < 0) {  
  13.         return result;  
  14.     }  
  15.   
  16.     memset(&addr, 0, sizeof(addr));  
  17.     namelen = strlen(property_service_socket);  
  18.     strlcpy(addr.sun_path, property_service_socket, sizeof addr.sun_path);  
  19.     addr.sun_family = AF_LOCAL;  
  20.     alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;  
  21.   
  22.     if(TEMP_FAILURE_RETRY(connect(s, (struct sockaddr *) &addr, alen)) < 0) {  
  23.         close(s);  
  24.         return result;  
  25.     }  
  26.   
  27.     r = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0));  
  28.   
  29.     if(r == sizeof(prop_msg)) {  
  30.         // We successfully wrote to the property server but now we  
  31.         // wait for the property server to finish its work.  It  
  32.         // acknowledges its completion by closing the socket so we  
  33.         // poll here (on nothing), waiting for the socket to close.  
  34.         // If you 'adb shell setprop foo bar' you'll see the POLLHUP  
  35.         // once the socket closes.  Out of paranoia we cap our poll  
  36.         // at 250 ms.  
  37.         pollfds[0].fd = s;  
  38.         pollfds[0].events = 0;  
  39.         r = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */));  
  40.         if (r == 1 && (pollfds[0].revents & POLLHUP) != 0) {  
  41.             result = 0;  
  42.         } else {  
  43.             // Ignore the timeout and treat it like a success anyway.  
  44.             // The init process is single-threaded and its property  
  45.             // service is sometimes slow to respond (perhaps it's off  
  46.             // starting a child process or something) and thus this  
  47.             // times out and the caller thinks it failed, even though  
  48.             // it's still getting around to it.  So we fake it here,  
  49.             // mostly for ctl.* properties, but we do try and wait 250  
  50.             // ms so callers who do read-after-write can reliably see  
  51.             // what they've written.  Most of the time.  
  52.             // TODO: fix the system properties design.  
  53.             result = 0;  
  54.         }  
  55.     }  
  56.   
  57.     close(s);  
  58.     return result;  
  59. }  
设置属性的请求在这里被通过socket发送出去。

Java层设置属性的方法位于SystemProperties类中,在该类中实现了一系列set/get方法,Java代码中就是通过这些set/get方法设置和读取系统属性的。

@/framework/base/core/ java/android/os/SystemProperties.java

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Set the value for the given key. 
  3.  * @throws IllegalArgumentException if the key exceeds 32 characters 
  4.  * @throws IllegalArgumentException if the value exceeds 92 characters 
  5.  */  
  6. public static void set(String key, String val) {  
  7.     if (key.length() > PROP_NAME_MAX) {  
  8.         throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);  
  9.     }  
  10.     if (val != null && val.length() > PROP_VALUE_MAX) {  
  11.         throw new IllegalArgumentException("val.length > " +  
  12.             PROP_VALUE_MAX);  
  13.     }  
  14.     native_set(key, val);  
  15. }  
注意到这里最终会调用到native的set方法。
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. private static native void native_set(String key, String def);  
看到这里,接下来会调到那里去,相信大家应该都清楚了。。。
0 0