1. 小知識點
如果屬性名稱以“ro.”開頭叠萍,那么這個屬性被視為只讀屬性。一旦設(shè)置泼诱,屬性值不能改變。
如果屬性名稱以“persist.”開頭漆魔,當設(shè)置這個屬性時坷檩,其值也將寫入/data/property。
2. 實現(xiàn)原理
客戶端進程
系統(tǒng)屬性的讀寫采用標準的JNI調(diào)用native方法:
SystemProperties.java -> android_os_SystemProperties.cpp -> system_properties.c
這個通路屬于客戶端進程改抡。
系統(tǒng)屬性采用的是客戶端-服務(wù)端模式矢炼。
服務(wù)端進程啟動后數(shù)據(jù)已經(jīng)將系統(tǒng)屬性數(shù)據(jù)讀取到相應(yīng)的共享內(nèi)存中,保存在全局變量system_property_area阿纤;客戶端通過socket與服務(wù)端通信句灌。
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);
}
服務(wù)端進程
初始化
Property Service 運行在init守護進程中。
// \system\core\init\Init.c
int main(int argc, char **argv)
{
// 加載文件中的系統(tǒng)屬性
property_init();
// 啟動系統(tǒng)屬性服務(wù)端
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");
// 創(chuàng)建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";
}
// 監(jiān)聽
listen(property_set_fd, 8);
register_epoll_handler(property_set_fd, handle_property_set_fd);
}
}
用于服務(wù)的啟停
屬性“ ctrl.start ”和“ ctrl.stop ”是用來啟動和停止服務(wù)欠拾。例如:
// start boot animation
property_set("ctl.start", "bootanim");
前面handle_property_set_fd函數(shù)中會判斷系統(tǒng)屬性的前綴胰锌,如果是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){
//創(chuàng)建進程啟動服務(wù)
pid = fork();
execve(svc->args[0], (char**) svc->args, (char**) ENV);
//修改服務(wù)的系統(tǒng)屬性 執(zhí)行狀態(tài)
notify_service_state(svc->name, "running");
}
獲取并保存所有定義的系統(tǒng)屬性
前面init中會調(diào)用property_init函數(shù):
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函數(shù)中會打開屬性共享內(nèi)存,并記入__system_property_area變量藐窄;