android系统之属性系统详解.docx

上传人:b****5 文档编号:7889647 上传时间:2023-01-27 格式:DOCX 页数:43 大小:1.66MB
下载 相关 举报
android系统之属性系统详解.docx_第1页
第1页 / 共43页
android系统之属性系统详解.docx_第2页
第2页 / 共43页
android系统之属性系统详解.docx_第3页
第3页 / 共43页
android系统之属性系统详解.docx_第4页
第4页 / 共43页
android系统之属性系统详解.docx_第5页
第5页 / 共43页
点击查看更多>>
下载资源
资源描述

android系统之属性系统详解.docx

《android系统之属性系统详解.docx》由会员分享,可在线阅读,更多相关《android系统之属性系统详解.docx(43页珍藏版)》请在冰豆网上搜索。

android系统之属性系统详解.docx

android系统之属性系统详解

android系统之属性系统详解

   

 

1属性系统概述

 属性property系统是android的一个重要特性。

它作为一个服务运行,管理系统配置和状态。

所有这些配置和状态都是属性。

每个属性是一个键值对(key/valuepair),其类型都是字符串。

         从功能上看,属性与windows系统的注册表非常相似。

         属性系统的架构如下图所示。

         图中有3个进程、一组永久属性文件和一块共享内存区域。

共享内存区域是所有属性记录的临时存储所在。

propertyservice:

只有该进程才可以写入共享内存区域,它负责从永久文件中加载属性记录

并将它们保存在共享内存中。

propertyconsumer:

该进程将共享内存加载到其自身的虚拟地址空间,并直接访问这些属性。

这并不是一个特定的进程,是加载属性的read操作库的客户端统称。

propertysetter:

该进程同样将共享内存加载到其自身的虚拟地址空间,但其不能直接写该内存。

setter试图增加或者更新一个属性时,它将该属性通过unixdomainsocket发送至

propertyservice服务进程。

注意:

后两者实际并不是一个特定的进程,是加载属性的get和set操作库的客户端进程统称。

下面以海思3798MV100平台(android4.4.2)为例来分析属性系统。

2property数据的编译

属性文件的生成依赖于build/core/Makefile文件,该文件实际上主导所有文件的编译,我们这里主要看其中的属性文件的编译引导。

2.1/default.prop

这是根目录下的属性文件,该属性文件的主要内容是adb控制相关的属性:

编译后该文件的输出:

1)\out\target\product\i3798MV100\root\default.prop

build/core/Makefile中对default.prop的编译引导如下:

TARGET_ROOT_OUT就是\out\target\product\i3798MV100\root\,对应设备文件系统的根目录。

可见该属性文件的内容来自于build/tools/post_process_props.py,该py文件根据环境的设定,来设置相关的adb控制属性。

2)\out\target\product\i3798MV100\recovery\root\default.prop

recovery系统是boot启动后的另外一个程序分支,所以这里面也需要一个属性文件,

build/core/Makefile中对default.prop拷贝了一份到recovery\root\下,TARGET_RECOVERY_ROOT_OUT就是\out\target\product\i3798MV100\recovery\root\

2.2/system/build.prop

这是system分区下的属性文件,该文件收集的属性信息较多,也是打交道最多的属性文件。

主要内容是常用的版本信息,平台信息,其他设备控制信息等:

编译后该文件放在\out\target\product\i3798MV100\system\build.prop,

TARGET_OUT就是\out\target\product\i3798MV100\system\,也就是system分区在设备文件系统下的对应目录。

build/core/Makefile中对build.prop的编译引导如下:

在build.prop的编译中,定义了BUILD_FINGERPRINT,BUILD_DISPLAY_ID等变量,都在build/tools/buildinfo.sh中被引用。

由上面的mk文件片段也可以看出build.prop的生成依赖于

 

1)引入BUILDINFO_SH的内容

数据来源:

build/tools/buildinfo.sh

BUILDINFO_SH在本文件定义,为BUILDINFO_SH:

=build/tools/buildinfo.sh。

最后通过bash$(BUILDINFO_SH)>$@解析得到buildinfo.sh中的全部属性。

2)引入INTERNAL_BUILD_ID_MAKEFILE的内容

数据来源:

/build/core/build_id.mk

INTERNAL_BUILD_ID_MAKEFILE在./build/core/version_defaults.mk中定义:

BUILD_SYSTEM在/build/core/main.mk中定义

所以INTERNAL_BUILD_ID_MAKEFILE就是/build/core/build_id.mk。

这里的作用仅仅是引入build_id.mk中定义的BUILD_ID变量。

3)引入(BUILD_SYSTEM)/version_defaults.mk的内容

数据来源:

/build/core/version_defaults.mk

即/build/core/version_defaults.mk,这里也主要是引入version_defaults.mk中的多个变量。

4)引入system_prop_file的内容

数据来源:

实际不存在

system_prop_file是在build.prop生成的末尾阶段以下面的方式引入的

system_prop_file自身是在该Makefile文件中定义的,如下:

经find命令搜索,TARGET_SYSTEM_PROP没有找到定义,所以走下一条路径,而TARGET_DEVICE_DIR在/build/core/config.mk中定义:

这段代码的意思TARGET_DEVICE_DIR就是Boardconfig.mk文件所在的目录,那么就应该是/device/hisilicon/Hi3798MV100

(注:

经过在Makefile中打印TARGET_DEVICE_DIR:

$(warning******TARGET_DEVICE_DIR:

$(TARGET_DEVICE_DIR)******),也确实是该目录

)。

所以这里就是要加载/device/hisilicon/Hi3798MV100下的system.prop,不过本平台在该目录下没有这个文件,所以system_prop_file的加载在这里是没有意义的

(注:

经过在Makefile中打印TARGET_DEVICE_DIR:

$(foreachfile,$(system_prop_file),\

warning***********system_prop1111file:

$(file)*************)

也确实打印不出任何目录)。

mr

5)引入ADDITIONAL_BUILD_PROPERTIES的内容

数据来源:

\build\core\product_config.mk

\device\hisilicon\Hi3798MV100\下的customer.mk和device.mk

\build\core\main.mk:

ADDITIONAL_BUILD_PROPERTIES是在build.prop生成的最后阶段以下面的方式引入的

ADDITIONAL_BUILD_PROPERTIES这个变量自身是在该Makefile文件中定义的,如下:

ADDITIONAL_BUILD_PROPERTIES最主要的作用就是引入另一个变量PRODUCT_PROPERTY_OVERRIDES,而这是在\build\core\product_config.mk中完成的:

ADDITIONAL_BUILD_PROPERTIES:

=\

$(ADDITIONAL_BUILD_PROPERTIES)\

$(PRODUCT_PROPERTY_OVERRIDES)

PRODUCT_PROPERTY_OVERRIDES的实际内容就很多了,它在\device\hisilicon\Hi3798MV100\下的customer.mk和device.mk,\build\core\main.mk等文件中都大量增加各种属性,也由此被引入到build.prop中。

如\device\hisilicon\Hi3798MV100\下的customer.mk下:

2.3其他属性文件

开机启动时,属性系统还要加载以下3个文件或目录,但是他们要么一般不使用(前2者),要么是运行时生成(后者)。

/*经验证,在3798MV100平台上并不存在*/

#definePROP_PATH_SYSTEM_DEFAULT"/system/default.prop"

#definePROP_PATH_LOCAL_OVERRIDE"/data/local.prop"

/*这是存储persist属性的目录,所有persist属性被各自写为文件存储在这里*/

#definePERSISTENT_PROPERTY_DIR"/data/property"

3property的相关实现代码和流程

propertyservice运行于init进程中。

init进程首先创建一个共享内存区域,该内存实际是一个虚拟文件,打开并保存其fd。

init进程将该区域通过使用了MAP_SHARED标志的mmap映射至它自身的虚拟地址空间,这样,任何对于该区域的更新对于所有进程都是可见的。

fd和区域大小被存储在一个名为ANDROID_PROPERTY_WORKSPACE的变量中。

任何其他进程,比如consumer和setter将使用这个变量来获得fd和尺寸,这样它们就能mmap这个区域到它们自身的虚拟地址空间中。

该共享内存区域如下图所示:

3.1property服务端解析

3.1.1Server端代码流程

3.1.1.1init.c下的整体流程

代码路径:

\system\core\init\init.c

整个属性系统的server端都运行在init进程中,在该文件的main函数中有简明扼要的流程线索,见下面代码截图的8个要点:

下面仔细分析这8个环节。

3.1.1.2创建共享内存区域

经分析,实际该共享内存是通过共享文件+镜像内存看来实现的,只不过文件本身是虚拟设备文件,也活动在内存中,所以也可以理解为共享内存。

1)源头:

\system\core\init\init.c下的main函数:

2)进入\system\core\init\property_service.c:

进入property_init

进入init_property_area

3)进入\bionic\libc\bionic\system_properties.c

进入函数map_prop_area_rw:

特别注意:

a、mmap实现镜像内存

将文件和内存进行映射,文件内容对内存是透明的,同时对该内存的操作也会同步修改文件内容。

b、内存共享是变相实现,是共享文件+镜像内存,并非真正的共享内存。

从上面可以看出,android属性系统的property_area本质上不是共享内存,而是共享文件,各进程只是创建了对该文件的内存镜像,且只有init进程(中的pro[erty_service)的镜像具备写入权限。

(当然该文件也是内存中的虚拟文件,所以说是共享内存也说得过去,不过这是变相的,不是使用共享内存的相关API)。

4)进程间共享文件

从上面的分析可以看到:

a、这里共享内存是基于共享文件。

b、共享的文件是property_filename

\bionic\libc\include\sys\_system_properties.h下定义:

#definePROP_FILENAME"/dev/__properties__"

\bionic\libc\bionic\system_properties.c下定义:

staticcharproperty_filename[PATH_MAX]=PROP_FILENAME;

c、操作property的进程间需要共享/dev/__properties__

那么/dev/__properties__文件到底是怎么共享的就需要被搞清楚了。

d、gcc之__libc_prenit特性实现文件共享

Android利用了gcc编译中的constructor属性,这个属性指明了一个__libc_prenit函数,当libc库被加载时,将自动调用这个__libc_prenit函数,android正是把/dev/__properties__的共享加入到这个函数内部,并进一步完成该共享文件到本地进程的映射工作。

简而言之,哪个进程加载libc,就加入了property系统的共享文件+镜像内存机制。

\bionic\libc\bionic\libc_init_dynamic.cpp

\bionic\libc\bionic\libc_init_common.cpp

5)\bionic\libc\bionic\system_properties.c

map_prop_area和map_prop_area_rw就只有文件打开方式,文件映射镜像内存的方式等方面的区别了

关于GCC中的constructor详细描述,请参照附录一《GCC中的constructor属性》

6)返回\system\core\init\property_service.c:

继续看init_property_area函数流程,进入:

再看init_workspace:

这个地方其实就是创建init进程下操作该共享文件的句柄而已,并保存在pa_workspace.全局变量中。

3.1.1.3加载根目录下的default.prop

1)源头:

\system\core\init\init.c下的main函数:

2)进入\system\core\init\property_service.c

PROP_PATH_RAMDISK_DEFAULT在\bionic\libc\include\sys\_system_properties.h中定义:

#definePROP_PATH_RAMDISK_DEFAULT"/default.prop"

注意加载属性的最后一步是把解析出来的属性通过property_set直接设置到镜像内存中,该函数的具体分析我们放到后面。

 

3.1.1.4加载其余4个属性文件的全部属性,并启动socket监听

1)源头

\system\core\init\init.c下的main函数:

将property_service_init_action标记为property_service_init加入到执行队列,在后面的while中去执行

\bionic\libc\include\sys\_system_properties.h中定义:

#definePROP_PATH_SYSTEM_BUILD"/system/build.prop"

#definePROP_PATH_SYSTEM_DEFAULT"/system/default.prop"

#definePROP_PATH_LOCAL_OVERRIDE"/data/local.prop"

#definePERSISTENT_PROPERTY_DIR"/data/property"

下面接着看property_service_init_action到底做了些什么

2)\system\core\init\init.c下的property_service_init_action

3)进入\system\core\init\property_service.c:

注意最后一个/data/property不是文件,是一个目录,下面每一个属性都存储为一个文件。

重点注意create_socket,这个函数要完成创建socket,绑定本地通讯端口等。

首先传入create_socket的PROP_SERVICE_NAME的定义:

\bionic\libc\include\sys\_system_properties.h中定义

#definePROP_SERVICE_NAME"property_service"

create_socket中用到的ANDROID_SOCKET_DIR的定义:

\system\core\include\cutils\sockets.h

#defineANDROID_SOCKET_DIR"/dev/socket"

4)进入\system\core\init\util.c

最终新创建的socket绑定到/dev/socket/property_service文件,实际就是localsocket的进程通讯模式。

3.1.1.5property触发器执行函数加入队列

将init.rc这里rc脚本文件解析出来的所有和property相关的触发器加入执行队列

1)源头:

\system\core\init\init.c下的main函数:

2)\system\core\init\init.c下的queue_property_triggers_action

3)\system\core\init\init_parser.c中的queue_all_property_triggers

3.1.1.6执行队列中的property任务

源头:

\system\core\init\init.c下的main函数:

进入execute_one_command:

不断通过外部循环获取队列中的action来执行。

注意这里面有一个隐藏任务:

当execute_one_command执行的是请一个service进程的时候,这里面还顺带完成了将proparea内存区的pa_workspace注册到环境变量的工作,以便其他进程也可以读取该变量。

3.1.1.7将property的监听socket加入待检查的socket数组

源头:

\system\core\init\init.c下的main函数:

进入\system\core\init\property_service.c,这里get_property_set_fd返回的property_set_fd正是步骤3.1.1.4创建的监听socket。

3.1.1.8检查上层有哪些端口连接请求

源头:

\system\core\init\init.c下的main函数:

3.1.1.9property设置的响应

1)源头:

\system\core\init\init.c下的main函数:

2)进入\system\core\init\property_service.c的handle_property_set_fd

这里的知识点较多,需要仔细分析:

这里面对属性的设置出现了两个分支:

3)ctl开头的属性控制sercive的起停

ctl开头的属性,是用来支持上层对特定service进行起停控制的,check_control_perms会检查要控制的属性的权限,handle_control_message真正处理service的控制。

比如dhcp相关的一个处理:

init.3798MV100.rc脚本中定义了dhcp的服务:

iprenew_eth0

\system\core\libnetutils\dhcp_utils.c中dhcp_do_request_renew函数:

传递到\system\core\init\property_service.c的handle_property_set_fd中:

msg.name为ctl.start,msg.value为iprenew_eth0。

再进入到\system\core\init\init.c下的handle_control_message,

msg为start,args为iprenew_eth0,继续进入到msg_start,里面就是很熟悉的service的启动操作service_start了。

通过这样的流程,完成了对应应用层通过虚拟属性ctl控制系统服务的响应,ctl开头的属性本质上可以看成仅仅是通过socket发送的一种系统消息。

可以类推setprop ctl.start iprenew_eth0都能启动dhcp。

4)响应其他属性的setpprop请求

首先完成对上层请求setprop的进程的权限检查,权限足够就进入property_set,注意这个是server端property_service.c里面的property_set。

这里的权限检查函数,有助于我们理解哪些属性需要什么样的权限,再遇到上层无法设置某些属性的时候就能迅速知道原因了:

白名单如下:

根据这个列表,在应用程序apk中如果想设置某类属性,则只需要将该apk在主xml中设置对应的权限即可。

另外上下文安全策略相关的东西check_mac_perms见附录,和本文的主体关系不大,暂且略过。

 

至此,server端的属性初始化和设置响应流程就完成了。

 

3.1.2详解server端的property_set

相关源代码:

\system\core\init\property_service.c

\bionic\libc\bionic\system_properties.c

服务端的property_set流程控制实现在property_service.c中,但是其调用的函数实现都在

system_properties.c中,后者以libc.a库的形势被引入。

整个设置过程上面已经很清楚,其中有几个主要环节:

3.1.2.1__system_property_find

相关源代码:

\bionic\libc\bionic\system_properties.c

该函数的作用是根据属性名称找到该属性在镜像内存中的对应内存,并返回其数据指针*prop_info。

从这里可以看到,root_node返回的就是__system_property_area__->data,即跳过了镜像内存的头信息之后的纯属性数据区首地址。

3.1.2.2find_property

相关源代码:

\bionic\libc\bionic\system_properties.c

接下来的find_property函数里面涉及到二叉树树形结构算法,技巧很强,阅读有一定难度。

从该函数可以看出当alloc_if_needed为true的时候,find_property同时承担了分配新属性的树形索引区prop_bt内存和真正的数据区内存prop_info的功能;prop_info的真正地址就挂在末

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 医药卫生 > 临床医学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1