1. 小知识点
如果属性名称以“ro.”开头,那么这个属性被视为只读属性。一旦设置,属性值不能改变。
如果属性名称以“persist.”开头,当设置这个属性时,其值也将写入/data/property。
2. 实现原理
客户端进程
系统属性的读写采用标准的JNI调用native方法:
SystemProperties.java -> android_os_SystemProperties.cpp -> system_properties.c
这个通路属于客户端进程。
系统属性采用的是客户端-服务端模式。
服务端进程启动后数据已经将系统属性数据读取到相应的共享内存中,保存在全局变量system_property_area;客户端通过socket与服务端通信。
int __system_property_set(const char *key, const char *value)
{
msg.cmd = PROP_MSG_SETPROP;
strlcpy(msg.name, key, sizeof msg.name);
strlcpy(msg.value, value, sizeof msg.value);
err = send_prop_msg(&msg);
}
static int send_prop_msg(prop_msg *msg)
{
//sokcet 通信 /dev/socket/property_service
s = socket(AF_LOCAL, SOCK_STREAM, 0);
connect(s, (struct sockaddr *) &addr, alen)
send(s, msg, sizeof(prop_msg), 0)
close(s);
}
服务端进程
初始化
Property Service 运行在init守护进程中。
// \system\core\init\Init.c
int main(int argc, char **argv)
{
// 加载文件中的系统属性
property_init();
// 启动系统属性服务端
start_property_service();
while (true) {
// By default, sleep until something happens.
int epoll_timeout_ms = -1;
if (do_shutdown && !shutting_down) {
do_shutdown = false;
if (HandlePowerctlMessage(shutdown_command)) {
shutting_down = true;
}
}
if (!(waiting_for_prop || Service::is_exec_service_running())) {
am.ExecuteOneCommand();
}
if (!(waiting_for_prop || Service::is_exec_service_running())) {
if (!shutting_down) {
auto next_process_restart_time = RestartProcesses();
// If there's a process that needs restarting, wake up in time for that.
if (next_process_restart_time) {
epoll_timeout_ms = std::chrono::ceil<std::chrono::milliseconds>(
*next_process_restart_time - boot_clock::now())
.count();
if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
}
}
// If there's more work to do, wake up again immediately.
if (am.HasMoreCommands()) epoll_timeout_ms = 0;
}
epoll_event ev;
int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms));
if (nr == -1) {
PLOG(ERROR) << "epoll_wait failed";
} else if (nr == 1) {
((void (*)()) ev.data.ptr)();
}
}
}
\system\core\init\property_service.c:
void start_property_service(void)
{
void start_property_service() {
selinux_callback cb;
cb.func_audit = SelinuxAuditCallback;
selinux_set_callback(SELINUX_CB_AUDIT, cb);
property_set("ro.property_service.version", "2");
// 创建sokcet
property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
false, 0666, 0, 0, nullptr);
if (property_set_fd == -1) {
PLOG(FATAL) << "start_property_service socket creation failed";
}
// 监听
listen(property_set_fd, 8);
register_epoll_handler(property_set_fd, handle_property_set_fd);
}
}
用于服务的启停
属性“ ctrl.start ”和“ ctrl.stop ”是用来启动和停止服务。例如:
// start boot animation
property_set("ctl.start", "bootanim");
前面handle_property_set_fd函数中会判断系统属性的前缀,如果是ctl开头则做以下处理:
void handle_control_message(const char *msg, const char *arg)
{
if (!strcmp(msg,"start")) {
msg_start(arg);
} else if (!strcmp(msg,"stop")) {
msg_stop(arg);
} else if (!strcmp(msg,"restart")) {
msg_stop(arg);
msg_start(arg);
}
}
static void msg_start(const char *name)
{
service_start(svc, args);
}
void service_start(struct service *svc, const char *dynamic_args){
//创建进程启动服务
pid = fork();
execve(svc->args[0], (char**) svc->args, (char**) ENV);
//修改服务的系统属性 执行状态
notify_service_state(svc->name, "running");
}
获取并保存所有定义的系统属性
前面init中会调用property_init函数:
void property_init() {
mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH);
CreateSerializedPropertyInfo();
if (__system_property_area_init()) {
LOG(FATAL) << "Failed to initialize property area";
}
if (!property_info_area.LoadDefaultPath()) {
LOG(FATAL) << "Failed to load serialized property info file";
}
}
__system_property_area_init函数中会打开属性共享内存,并记入__system_property_area变量;