属性系统是Android的一个重要特性,属性由属性名称和键值组成的一段字符串,又称键值对,用于记录系统设置或进程信息交换。属性在整个系统全局可见,每个进程可通过property_get/property_set获取和设置属性。本篇主要介绍移植版本的Property大致流程。
Property机制主要由服务端进程与客户端进程组成。property服务端进程用于初始化存储属性的共享空间、监听客户端请求、增加属性键值对和更新属性对应键值等功能。客户端为使用Property的应用进程,主要通过调用poperty_set和property_get集来实现设置和获取属性键值。
移植版本Property与Android原生Property使用方法有一些区别:
(1) Android是在init进程初始化Property服务端。移植版本则将Property服务端设计为独立进程,在开机启动时启用Property服务。如此设计的优点在于,将Property服务设计为独立的模块,便于各个应用移植和使用。
(2) Android在使用Property机制时会核对使用进程Selinux权限,在进程使用property_set/property_get时,会先审核使用进程是否拥有访问该属性权限。移植版本Property则省去Selinux权限。
(3) 移植版本Property是在Android KitKat4.4基础上移植而来,其内部实现细节可能与4.4版本之后有所出入。
API介绍服务端:
本部分代码接口无需特殊关注,只需将编译的bin文件(Property_service)放入起始服务后台运行即可。Property服务端代码执行顺序需优先于客户端。
客户端:
客户端代码主要功能为设置和获取Property键值,以下为对外开放的接口。
设置Property
/*
* @description: 设置或增加属性键值
* @param - key: 需设置的属性名。
* @param - value: 属性名对应的键值。
* @return: 0 on success,< 0 on failure
*/int property_set(const char *key, const char *value)
获取Property
/*
* @description: 获取属性键值字符串
* @param - key: 需获取的属性名。
* @param - value: 属性名对应的键值。
* @param - default_value: 若获取失败,则使用此默认键值
* @return: 成功返回属性值长度,获取错误返回0
*/int property_get(const char *key, char *value, const char *default_value)
/*
* @description:用于获取bool类型的属性,失败返回默认值default_value
*/int8_t property_get_bool(const char *key, int8_t default_value)
/*
* @description:用于获取64位类型的属性,失败返回默认值default_value
*/int64_t property_get_int64(const char *key, int64_t default_value)
/*
* @description:用于获取32位类型的属性,失败返回默认值default_value
*/int32_t property_get_int32(const char *key, int32_t default_value)
注:系统中存在的key字符长度最大为32,value字符长度最大为92。如有越过,会导致异常情况。
特殊类型属性:
“ro.”前缀: “ro.”前缀,只读属性。仅会被设置一次,即当设置此属性发现其属性名已经存在,则此次设置不会生效,返回-1。
“persist.”前缀: “persist.”前缀,保留属性。当服务端接收到persist属性设置请求时,会在/data/property目录下建立对应的属性文件,并将键值存储到此文件中。如此一来即可实现键值掉电存储功能。
实现机制流程:简单的介绍,Property机制运作流程可以简单的概括为以下几步:
- PropertyService服务启动,初始化共享内存,加载若干属性脚本中默认属性内容;
- 将系统中所有属性内容(key/value)存入系统共享内存,创建socket,并持续监听客户端socket请求;
- 系统中各个客户进程将共享内存(只读权限)映射到自己的内存空间,可直接读取属性内容;
- 系统仅有Property Service (属性服务)可修改和增加属性值;
- 各个客户进程仅有读取属性权限,如需修改属性,需通过socket方式向Property Service发出修改请求,由Property Service统一修改;
- 属性键值内容以字典树的形式存储于共享内存中(二叉树)。
Property机制示意图:
代码分析:
- Property Service:Property服务端实现内容主要包括两部分:存储属性值共享内存(mmap + 二叉树)和建立通信(socket)。 共享机制:将文件映射两次到内存,第一次为可读可写权限,句柄为property service服务;第二次为只读权限,句柄为client服务。 通信机制:服务端建立socket通信,持续监听并处理客户端请求。
- Property Client:
客户端功能主要为设置属性和获取属性。其中获取属性可直接读取共享内存即可;设置属性则需要向服务端发送申请,由服务端将属性键值对设置到共享内存。property_set流程:
property_get流程:
使用示例在使用之前先在后台执行服务端程序property_service(可放到开机启动脚本)。
image.png
注:在一次开机中只允许执行一次property_service。若希望在property_service出现异常,手动重新执行,需先删除共享文件"dev/__properties__"。
显示系统设置的属性:
手动设置属性:
总结- 本篇主要记录移植Android Property机制过程以及对其原理的简要分析,Property可实现多进程之间的数据交互功能。
- Property机制主要使用了socket、mmap和二叉树的技巧,学习其整体的设计可为后续工作开发增加知识储备。
最后
用心感悟,认真记录,写好每一篇文章,分享每一框干货。愿每一篇文章不负自己,不负看客!文章所有实现代码,均可在后台发送关键字获取。
猜你喜欢
详解 | Linux系统是如何实现存储并读写文件的?
更多文章内容包括但不限于C/C++、Linux、开发常用神器等,可进入开源519公众号聊天界面回复“文章目录” 或者 菜单栏选择“文章目录”查看。
本文摘自 :https://blog.51cto.com/u