一、Android4.4属性系统系列文章
Android4.4属性系统-初始化
Android4.4属性系统-系统服务
Android4.4属性系统-内存空间共享
Android4.4属性系统-属性获取
Android4.4属性系统-属性设置
二、写在前面-如何阅读本系列文章
本系列文章大部分是对源码的解析和注释,所以读起来枯燥无味,并且杂乱,这是阅读系统源码无法避免的,如果你有条件,可以点击下载Android4.4源码,阅读源码可以使用eclise,AndroidStudio,vim等。
文章的章节安卓是按照代码模块区分的,例如init进程代码,libcutils代码是按章节来区分,但不同模块的代码之间是有关联的,阅读时需要经常跳转,通过搜索功能进行页内搜索即可
三、安卓属性系统介绍
Android 里有很多属性(property),每个属性都有一个名字和值,他们都是字符串格式。这些属性定义了 Android 系统的一些公共系统属性。
在Android平台中,为了让运行中的所有进程共享系统运行时所需要的各种设置值,系统开辟了属性存储区域,并提供了访问该区域的API。属性由键(key)与值(value)构成,其表现形式为“键=值”。
在访问属性值时,添加了访问权限控制,增强了访问的安全性。系统中所有运行中的进程都可以访问属性值,但仅有init进程才能修改属性值。其他进程修改属性值时,必须向init进程提出请求,最终由init进程负责修改属性值。在此过程中,init进程会先检查各属性的访问权限,而后再修改属性值。
当属性值更改后,若定义在init.rc文件中的某个特定条件得到满足,则与此条件相匹配的动作就会发生,每个动作都有一个触发器,决定动作的执行时间,记录在“on property”关键字后的命令即被执行。
3.1属性系统工作框架
从图中我们可以看出Android属性系统由有三个进程,一组属性文件和一块共享内存组成。这块共享内存保存着系统中所有的属性记录,只有Property service能写这块共享内存,并且Property service负责将属性文件中的属性记录加载到共享内存中。 **属性读取进程**(property consumer)把这块共享内存映射到自己的进程空间,然后直接读取它。**属性设置进程**(property setter)也加载这块共享到他的进程空间,但是他不能直接写这块共享内存。当他需要增加或者修改属性的时候,通过Unix Socket发生属性给Property service,Property service将代表设置进程写入共享内存和属性文件。 Property service运行于**init进程**中。init进程首先创建一块共享内存,并把他的句柄fd存放在这块内存中,**init进程通过mmap带MAP_SHARE标志的系统调用,把这块内存映射到他的虚拟空间中,最终这块内存所有的更新将会被所有映射这块共享内存的进程看到**。共享内存句柄fd和共享内存大小存储在系统环境变量“ANDROID_PROPERTY_WORKSPACE”中,所有的进程包括属性设置进程和属性读取进程都将通过这个系统环境变量获得共享内存的句柄fd和大小,然后把这块内存映射到他们自己的虚拟空间。共享内存布局如下:
当前,属性不能被删除。也就是说一旦属性被创建,将不可以被删除,但是它们可以被修改
四、属性系统的优点
属性系统有一下四个优点
- 全局性:只要拥有对应的权限,就可以同步获取和修改
- 广泛的可访问性:在Java层,native层,shell层都可以获取和修改
- 初始化早:属性服务实在 init 进程中启动的
- 使用简单:主要就两个方法 set 和 get
但是只能支持有限的类型:string、int、long、boolean
五、属性系统的初始化和启动过程
属性服务的是从init进程中启动,init 进程(源码位于/system/core/init/init.c)主要完成:
- 解析 init.rc 文件并执行相应动作和服务
- 生成设备驱动节点
- 处理子进程终止
- 提供属性服务
先上图熟悉流程:
5.1 init进程初始化property_service
init进程是安卓系统第一个进程,由它执行系统的初始化过程,属性服务也是由它开始初始化的
system/core/init/init.h
init.h是init.c的头文件,它定义了两个重要的结构体:command和action
#include <cutils/list.h> struct command { /* list of commands in an action */ struct listnode clist; //listnode结构体定义在list.h //command 结构体中的func指向一个函数,该函数在后续init 进程调用execute_one_command 时会被调用 int (*func)(int nargs, char **args); int nargs; char *args[1]; }; struct action { /* node in list of all actions */ struct listnode alist; /* node in the queue of pending actions */ struct listnode qlist; /* node in list of actions for a trigger */ struct listnode tlist; unsigned hash; const char *name; struct listnode commands; //listnode结构体定义在list.h struct command *current; };
system/core/init/init.c
init.c是init进程的源文件,找到入口main()函数
//引入property相关的头文件 #include <sys/system_properties.h> #include "property_service.h" static int property_triggers_enabled = 0; static struct action *cur_action = NULL; static struct command *cur_command = NULL; static struct listnode *command_queue = NULL; int main(int argc, char **argv) { int property_set_fd_init = 0; //1-property初始化,位于property_service.c property_init(); //2-这些目录必须在初始策略加载之前创建,因此需要将其安全上下文恢复到正确的值。这必须在由ueventd填充/dev之前发生。 restorecon("/dev"); restorecon("/dev/socket"); restorecon("/dev/__properties__"); restorecon_recursive("/sys"); is_charger = !strcmp(bootmode, "charger"); INFO("property init\n"); //3-如果不是充电状态,加载默认properties if (!is_charger) property_load_boot_defaults(); // queue_builtin_action()将 property_init_action函数放入特定的列表中 queue_builtin_action(property_service_init_action, "property_service_init"); /* run all property triggers based on current state of the properties */ queue_builtin_action(queue_property_triggers_action, "queue_property_triggers"); //进入for循环, for(;;) { int nr, i, timeout = -1; execute_one_command();//execute_one_command 函数从 action_queue 队列中获取 action 并执行 restart_processes(); if (!property_set_fd_init && get_property_set_fd() > 0) { ufds[fd_count].fd = get_property_set_fd(); ufds[fd_count].events = POLLIN; ufds[fd_count].revents = 0; fd_count++; property_set_fd_init = 1; } if (!signal_fd_init && get_signal_fd() > 0) { ufds[fd_count].fd = get_signal_fd(); ufds[fd_count].events = POLLIN; ufds[fd_count].revents = 0; fd_count++; signal_fd_init = 1; } if (!keychord_fd_init && get_keychord_fd() > 0) { ufds[fd_count].fd = get_keychord_fd(); ufds[fd_count].events = POLLIN; ufds[fd_count].revents = 0; fd_count++; keychord_fd_init = 1; } if (process_needs_restart) { timeout = (process_needs_restart - gettime()) * 1000; if (timeout < 0) timeout = 0; } if (!action_queue_empty() || cur_action) timeout = 0; #if BOOTCHART if (bootchart_count > 0) { if (timeout < 0 || timeout > BOOTCHART_POLLING_MS) timeout = BOOTCHART_POLLING_MS; if (bootchart_step() < 0 || --bootchart_count == 0) { bootchart_finish(); bootchart_count = 0; } } #endif nr = poll(ufds, fd_count, timeout); if (nr <= 0) continue; for (i = 0; i < fd_count; i++) { if (ufds[i].revents == POLLIN) { if (ufds[i].fd == get_property_set_fd()) handle_property_set_fd(); else if (ufds[i].fd == get_keychord_fd()) handle_keychord(); else if (ufds[i].fd == get_signal_fd()) handle_signal(); } } } } //property发生改变 void property_changed(const char *name, const char *value) { if (property_triggers_enabled) queue_property_triggers(name, value); } static int queue_property_triggers_action(int nargs, char **args) { queue_all_property_triggers(); //位于init_parser.c /* enable property triggers */ property_triggers_enabled = 1; return 0; } //从action队列中读取action并执行 void execute_one_command(void) { int ret; //判断是获取一个新的 action 还是继续执行 action 的 commands 列表中的下一个 command if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) { //对于Android属性系统,是一个新的action,cur_action==NULL,cur_command==NULL //从 action_queue 中 获 取 action 并 赋 值 给 cur_action,定义在init_parser.c中 cur_action = action_remove_queue_head(); cur_command = NULL; if (!cur_action) return; INFO("processing action %p (%s)\n", cur_action, cur_action->name); //从 cur_action 中的 commands 节点中获取第一个 command 赋值给 cur_command cur_command = get_first_command(cur_action); } else { cur_command = get_next_command(cur_action, cur_command); } if (!cur_command) return; //对于 Android 属性系统,action 的 commands 节点只有一个 command,调用 //command中 func 成员所指向的函数,此处调用 property_service_init_action函数 ret = cur_command->func(cur_command->nargs, cur_command->args); INFO("command '%s' r=%d\n", cur_command->args[0], ret); } //从指定action结体中,获取commands链表的第一个节点 static struct command *get_first_command(struct action *act) { struct listnode *node; node = list_head(&act->commands); if (!node || list_empty(&act->commands)) return NULL; return node_to_item(node, struct command, clist); } //Android属性服务初始化函数 static int property_service_init_action(int nargs, char **args) { /* read any property files on system or data and * fire up the property service. This must happen * after the ro.foo properties are set above so * that /data/local.prop cannot interfere with them. */ //该方法开始读取系统中所有的property文件或者数据,并启动Property服务,但是这 //必须在ro.foo的属性被设置之后,这样/data/local.prop就不会干扰它们 start_property_service(); //定义在property_service.c中 return 0; }