android native property属性

 

前几天在分析Camera的时候,有一段这样的代码 property_get("service.camera.hw", value,"base");从字面猜测这是获取属性值,但是怎么去获取?属性值又在哪设置的?决定等把Camera HAL理完了之后,把这个也分析一下。今天就粗略的看了并总结如下。

 

属性(property)是一对键/值(key/value)组合,键和值都是字符串类型。Androd中非常多的应用程序和库直接或者间接的依赖于属性系统,并由此决定其运行期的行为。它的处理流程同android的其他模块一样,也分为服务端客户端,property设置必须在服务端,读取直接在客户端。

架构图:

               android native property属性_第1张图片

服务端 :

我们就来看系统的守护进程init,服务断就在这个进程里,分析它的main()@system/core/init/init.c函数。
    
   1.  
 创建文件目录,打开中断设备,读取/init.rc,/init.**.rc。

       这些都跟我们要分析的关系不大,但是还是要说明一下读取.rc文件的过程:

       init有三个全局列表service_list,action_list,queue_list

       init.rc文件格式(截图):
                android native property属性_第2张图片

     当读取文件扫描到以on开头的一行数据时,将紧跟on后面的数据和下面几行数据组装成struct action@system/core/init/init.h变量,并加到action_list列表里。以service开头的就组装成strcut service@system/core/init/init.h变量,并加到service_list列表里。service_list记录了系统所有服务的列表;action_list记录了系统动作列表,但是相应的命令是不会运行的,除非将元素移动到queue_list列表;queue_list记录了将要执行的动作列表。

 
   2.   queue_builtin_action和action_for_each_trigger的调用

     其中跟property有关的调用如下:

    queue_builtin_action(property_init_action,"property_init");

    queue_builtin_action(property_service_init_action,"property_service_init");

     把第一个(函数)和第二个参数(名字)组装成一个action变量加到action_list和queue_list列表。

    action_for_each_trigger("init", action_add_queue_tail);在action_list列表里查找以init为名的action变量,找到后将它加到queue_list列表里

  
  3.   
进入死循环for(;;)

  
  4.  execute_one_command和restart_processes的调用

      执行所有在queue_list列表里的action,其中就有调用property_init_action和property_service_init_action它们分别调用property_init@system/core/init/Porpertys_services.c和start_property_servicet@system/core/init/Porpertys_services.c。运行service_list里的服务。

             (1) 申请共享内存ashmem_create_region("system_properties", PA_SIZE),共享内存的参数保存在pa_workspace,共享内存分两部分,__system_property_area__指向内存起始地址,pa_info_array指向内存起始地址加PA_INFO_START的地址。__system_property_area__用来记录属性列表的统计信息,pa_info_array就是记录属性列表的地方,属性的个数最多为PA_COUNT_MAX。其中涉及到的宏定义如下:

#define PA_COUNT_MAX  24 #define PA_INFO_START 1024 #define PA_SIZE       32768

共享内存的结构图:

           android native property属性_第3张图片
             (2) 从下面宏定义的文件及PERSISTENT_PROPERTY_DIR指定的目录下以
persist.开头的文件中读取属性列表并储存在共享内存中。

     #define PROP_PATH_RAMDISK_DEFAULT  "/default.prop"
     #define PROP_PATH_SYSTEM_BUILD     "/system/build.prop"
     #define PROP_PATH_SYSTEM_DEFAULT   "/system/default.prop"
     #define PROP_PATH_LOCAL_OVERRIDE   "/data/local.prop" 
     #define PERSISTENT_PROPERTY_DIR    "/data/property"

 文件内容的一般格式,从system/build.prop截的图

        android native property属性_第4张图片
                (3) 创建本地Socket,fd = socket(PF_UNIX, SOCK_STREAM, 0),路径是ANDROID_SOCKET_DIR/PROP_SERVICE_NAME。绑定路径监听Socket(非阻塞)。

    #define PROP_SERVICE_NAME  "property_service"
    #define ANDROID_SOCKET_DIR "/dev/socket"


                (4)启动service_list列表里的服务,在启动服务之前,将共享内存的句柄(当然是dup之后的)和大小保存在服务进程的环境变量里。

     sprintf(tmp, "%d,%d", dup(fd), sz);
    add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);//ENV[n] = tmp;   
    execve(svc->args[0], (char**)svc->args, (char**) ENV)

  5.   使用select函数,等待客户端Socket的连接。

    有连接到来,调用handle_property_set_fd函数处理,首先accept获取连接,getsockopt(s, SOL_SOCKET, SO_PEERCRED,&cr, &cr_size)获取到客户端权限;再接受数据,判断命令类型,现只接受一种命令PROP_MSG_SETPROP(修改property),在修改之前要判断客户端有没有相应的权限。命令有两种类型:''ctrl:start netd(服务名)''/''ctrl:stopnetd(服务名)'';''service.video.path(property名字)=normal(property值)'';第一种是用来启动停止服务的,与我们要分析的关系不大,第二种就是property的设置了调用property_set。

 

  6.    property_set@system/core/init/Property_service.c

    先根据property名字从pa_info_array指向的内存中查找,若查找到更新内存中的值,否则在内存的后面添加。并查找此property设置有没有相应的action,若存在则加到queue_list列表里,比如前面的init.rc文件有内容:

     on property:persist.service.adb.enable=1 
     start adbd
当调用property_set(“persist.service.adb.enable”,”1”)时,由于action_list存在这个action,将它加入到queue_list,就会触发这个action的动作start adbd(启动adbd服务)。 这里有几种特殊的情况:以ro.开头的property不可以修改,只能初始化一次;以net.开头的property同时设置''net.change=name'';以persist.开头的property同时创建以PERSISTENT_PROPERTY_DIR/name命名的文件并写入它的值。

    

客户端:

   JAVA程序可以通过SystemProperties@framework/base/core/java/anroid/os/SystemProperties.java类来修改和获得property,其实质还是调用到c++ 空间的property_get/property_set(system/core/libcutils/Properties.c)

  1.   获得property共享内存地址和大小

    在客户端进程初始化libc库的时候都会调用_libc_preint@bionic\libc\bionic\libc_init_dynamic.c(动态加载)或_libc_init@bionic\libc\bionic\libc_init_static.c(静态加载),这两个函数都会调用_libc_init_common@bionic/libc/bionic/libc_init_common.c,进一步调用__system_properties_init@bionic/libc/bionnic/System_properties.c。获取环境变量值getenv("ANDROID_PROPERTY_WORKSPACE"),得到内存句柄和大小,使用mmap得到内存地址 __system_property_area__。

  2. propety_get 直接在共享内存查找,这个不需要通过服务端。

  3. propety_set  连接上服务端socket,发送到服务端处理。

你可能感兴趣的:(android native property属性)