android开发----3.property分析

2160阅读 0评论2017-01-17 wangcong02345
分类:Android平台

android源码版本-->4.4.2
linux源码版本-->3.4
一. 总体分析



二.property的初始化
system/core/init.c中会调用property_init,
  1. void property_init(void)
  2. {
  3.     init_property_area();
  4. }
init/property_service.c中
  1. static int init_property_area(void)
  2. {
  3.     if (property_area_inited)
  4.         return -1;

  5.     if(__system_property_area_init())
  6.         return -1;

  7.     if(init_workspace(&pa_workspace, 0))
  8.         return -1;

  9.     fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC);

  10.     property_area_inited = 1;
  11.     return 0;
  12. }
在bionic/libc/bionic/system_properties.c中
  1. int __system_property_area_init()
  2. {
  3.     return map_prop_area_rw();
  4. }
在bionic/libc/bionic/system_properties.c中
  1. static int map_prop_area_rw()
  2. {
  3.     prop_area *pa;
  4.     int fd;
  5.     int ret;

  6.     //打开/dev/__properties__文件
  7.     //static char property_filename[PATH_MAX] = PROP_FILENAME;
        //#define PROP_FILENAME "/dev/__properties__"
  8.     fd = open(property_filename, O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC | O_EXCL, 0444);
  9.     if (fd < 0) {
  10.         if (errno == EACCES) {
  11.             abort();
  12.         }
  13.         return -1;
  14.     }

  15.     ret = fcntl(fd, F_SETFD, FD_CLOEXEC);  //FD_CLOEXEC表示执行exec函数时fd会关闭
  16.     if (ret < 0)
  17.         goto out;
  18.     //把文件设为128K大小
  19.     if (ftruncate(fd, PA_SIZE) < 0)   //include/sys/_system_properties.h中定义了#define PA_SIZE (128 * 1024)
  20.         goto out;

  21.     pa_size = PA_SIZE;
  22.     pa_data_size = pa_size - sizeof(prop_area);
  23.     compat_mode = false;

  24.     pa = mmap(NULL, pa_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);  //映射
  25.     if(pa == MAP_FAILED)
  26.         goto out;
  27.     //把映射的128K字段清0,同时共享内存的开始是结构体pa,设置一下pa
  28.     memset(pa, 0, pa_size);
  29.     pa->magic = PROP_AREA_MAGIC;
  30.     pa->version = PROP_AREA_VERSION;
  31.     pa->bytes_used = sizeof(prop_bt);

  32.     /* plug into the lib property services */
  33.     __system_property_area__ = pa;     //将全局变量__system_property_area__作为管理结构体

  34.     close(fd);
  35.     return 0;

  36. out:
  37.     close(fd);
  38.     return -1;
  39. }


三.property的读取与设置
以init/init.c中的export_kernel_boot_props为例说明
  1. static void export_kernel_boot_props(void)
  2. {
  3.     struct {
  4.         const char *src_prop;
  5.         const char *dest_prop;
  6.         const char *def_val;
  7.     } prop_map[] = {
  8.         { "ro.boot.serialno", "ro.serialno", "", },
  9.         { "ro.boot.mode", "ro.bootmode", "unknown", },
  10.         { "ro.boot.baseband", "ro.baseband", "unknown", },
  11.         { "ro.boot.bootloader", "ro.bootloader", "unknown", },
  12.     };
  13.     for (i = 1; i < ARRAY_SIZE(prop_map); i++) {
  14.         ret = property_get(prop_map[i].src_prop, tmp);       //先获取perperty中的字段,如果ret>0,说明找到了
  15.         if (ret > 0)
  16.             property_set(prop_map[i].dest_prop, tmp);
  17.         else
  18.             property_set(prop_map[i].dest_prop, prop_map[i].def_val);
  19.     }
  20.     ......
  21. }






3.1 读取的过程:在system/core/libcutils/properties.c中
因为在build/core/combo/include/arch/linux-arm/AndroidConfig.h中定义了HAVE_LIBC_SYSTEM_PROPERTIES,
所以poperty_get的实现如下所示:
  1. int property_get(const char *key, char *value, const char *default_value)
  2. {
  3.     int len;

  4.     len = __system_property_get(key, value);    //先去查找
  5.     if(len > 0) {
  6.         return len;
  7.     }
  8.     //如果没有找到,并且default_value不为空,就将value设为default_value
  9.     if(default_value) {                        
  10.         len = strlen(default_value);
  11.         memcpy(value, default_value, len + 1);
  12.     }
  13.     return len;
  14. }
bionic/libc/bionic/system_properties.c
  1. int __system_property_get(const char *name, char *value)
  2. {
  3.     const prop_info *pi = __system_property_find(name);   //先在mmap的共享内存中查找结点是否存在

  4.     if(pi != 0) {                                         //如果存在就去读取其value
  5.         return __system_property_read(pi, 0, value);
  6.     } else {                                              //如果不存在就把value设为0,注意value是个字符串
  7.         value[0] = 0;
  8.         return 0;
  9.     }
  10. }

3.2 写入的过程:在system/core/libcutils/properties.c中
  1. int property_set(const char *key, const char *value)
  2. {
  3.     return __system_property_set(key, value);
  4. }
bionic/libc/bionic/system_properties.c
  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.     //构造msg
  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.     //发送msg
  16.     err = send_prop_msg(&msg);
  17.     if(err < 0) {
  18.         return err;
  19.     }

  20.     return 0;
  21. }





  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.     s = socket(AF_LOCAL, SOCK_STREAM, 0);   //创建一个本地socket
  11.     if(s < 0) {
  12.         return result;
  13.     }

  14.     memset(&addr, 0, sizeof(addr));
  15.     namelen = strlen(property_service_socket);  //这个路径是/dev/socket/property_service
  16.     strlcpy(addr.sun_path, property_service_socket, sizeof addr.sun_path);
  17.     addr.sun_family = AF_LOCAL;
  18.     alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;

  19.     if(TEMP_FAILURE_RETRY(connect(s, (struct sockaddr *) &addr, alen)) < 0) {  //连接到server
  20.         close(s);
  21.         return result;
  22.     }

  23.     r = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0));              //发送数据到server

  24.     if(r == sizeof(prop_msg)) {                                             //如果发送成功
  25.         pollfds[0].fd = s;
  26.         pollfds[0].events = 0;
  27.         r = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */));             //则创建poll来监听server的回应
  28.         if (r == 1 && (pollfds[0].revents & POLLHUP) != 0) {
  29.             result = 0;
  30.         } else {
  31.             result = 0;
  32.         }
  33.     }

  34.     close(s);
  35.     return result;
  36. }



3.2.2 server是在哪开启的呢
init/init.c中-->     queue_builtin_action(property_service_init_action, "property_service_init");
  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. }



  1. void start_property_service(void)
  2. {
  3.     int fd;

  4.     load_properties_from_file(PROP_PATH_SYSTEM_BUILD);
  5.     load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);
  6.     load_override_properties();
  7.     /* Read persistent properties after all default values have been loaded. */
  8.     load_persistent_properties();

  9.     fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0);
  10.     if(fd < 0) return;
  11.     fcntl(fd, F_SETFD, FD_CLOEXEC);
  12.     fcntl(fd, F_SETFL, O_NONBLOCK);

  13.     listen(fd, 8);
  14.     property_set_fd = fd;           //把这个server的socket fd设为全局变量
  15.     #ifdef AW_BOOSTUP_ENABLE
  16.     aw_init_boostup();
  17.     #endif
  18. }





3.2.3 在init的最后
  1. int main(int argc, char **argv)
  2. {
  3.     .......
  4.     for(;;) {
  5.         int nr, i, timeout = -1;

  6.         execute_one_command();
  7.         restart_processes();

  8.         if (!property_set_fd_init && get_property_set_fd() > 0) {    //这个get_property_set_fd就是获取全局变量propety_set_fd
  9.             ufds[fd_count].fd = get_property_set_fd();               //把server端的socket fd 放到poll中监听
  10.             ufds[fd_count].events = POLLIN;
  11.             ufds[fd_count].revents = 0;
  12.             fd_count++;
  13.             property_set_fd_init = 1;
  14.         }
  15.         ....
  16.         nr = poll(ufds, fd_count, timeout);                          //在poll中监听socket fd
  17.         if (nr <= 0)
  18.             continue;

  19.         for (i = 0; i < fd_count; i++) {
  20.             if (ufds[i].revents == POLLIN) {
  21.                 if (ufds[i].fd == get_property_set_fd())            //如果是property的fd有变化则调用property的函数去处理
  22.                     handle_property_set_fd();
  23.                 else if (ufds[i].fd == get_keychord_fd())
  24.                     handle_keychord();
  25.                 else if (ufds[i].fd == get_signal_fd())
  26.                     handle_signal();
  27.             }
  28.         }
  29.     }

  30.     return 0;
  31. }




  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.     if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
  13.         return;
  14.     }

  15.     /* Check socket options here */
  16.     if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
  17.         close(s);
  18.         ERROR("Unable to receive socket options\n");
  19.         return;
  20.     }

  21.     r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), 0));
  22.     if(r != sizeof(prop_msg)) {
  23.         ERROR("sys_prop: mis-match msg size received: %d expected: %d errno: %d\n",
  24.               r, sizeof(prop_msg), errno);
  25.         close(s);
  26.         return;
  27.     }

  28.     switch(msg.cmd) {
  29.     case PROP_MSG_SETPROP:
  30.         msg.name[PROP_NAME_MAX-1] = 0;
  31.         msg.value[PROP_VALUE_MAX-1] = 0;

  32.         if (!is_legal_property_name(msg.name, strlen(msg.name))) {
  33.             ERROR("sys_prop: illegal property name. Got: \"%s\"\n", msg.name);
  34.             close(s);
  35.             return;
  36.         }

  37.         getpeercon(s, &source_ctx);

  38.         if(memcmp(msg.name,"ctl.",4) == 0) {   //处理ctl.开头消息
  39.             close(s);
  40.             if (check_control_perms(msg.value, cr.uid, cr.gid, source_ctx)) {
  41.                 handle_control_message((char*) msg.name + 4, (char*) msg.value);
  42.             } else {
  43.                 ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n"msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);
  44.             }
  45.         } else {
  46.             if (check_perms(msg.name, cr.uid, cr.gid, source_ctx)) {
  47.                 property_set((char*) msg.name, (char*) msg.value);           //真正的property_set
  48.             } else {
  49.                 ERROR("sys_prop: permission denied uid:%d name:%s\n"cr.uid, msg.name);
  50.             }

  51.             // Note: bionic's property client code assumes that the
  52.             // property server will not close the socket until *AFTER*
  53.             // the property is written to memory.
  54.             close(s);
  55.         }
  56.         freecon(source_ctx);
  57.         break;

  58.     default:
  59.         close(s);
  60.         break;
  61.     }
  62. }







上一篇:android开发----1.init进程分析
下一篇:android开发----4.parser分析