property_service是在init中启动的,
int main(int argc, char **argv){
property_init();
property_load_boot_defaults(); // 加载"/default.prop"
queue_builtin_action(property_service_init_action, "property_service_init");
// ...
void property_init(void){
init_property_area(); // 开始初始化property内存和workspace
}
static int init_property_area(void) {
if (property_area_inited)
return -1;
if(__system_property_area_init()) // 映射一块内存
return -1;
if(init_workspace(&pa_workspace, 0)) // 初始化workspace
return -1;
fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC);
property_area_inited = 1; // 初始化完成标记
return 0;
}
int __system_property_area_init(){
return map_prop_area_rw();
}
static int map_prop_area_rw(){
prop_area *pa;
int fd;
int ret;
/* dev is a tmpfs that we can use to carve a shared workspace
* out of, so let's do that...
*/
fd = open(property_filename, O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC | // 打开/dev/__properties__临时设备
O_EXCL, 0444);
if (fd < 0) {
if (errno == EACCES) {
/* for consistency with the case where the process has already
* mapped the page in and segfaults when trying to write to it
*/
abort();
}
return -1;
}
ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
if (ret < 0)
goto out;
if (ftruncate(fd, PA_SIZE) < 0) // 改变大小为128k
goto out;
pa_size = PA_SIZE;
pa_data_size = pa_size - sizeof(prop_area);
compat_mode = false;
// 映射出一块内存
pa = mmap(NULL, pa_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(pa == MAP_FAILED)
goto out;
memset(pa, 0, pa_size);
pa->magic = PROP_AREA_MAGIC;
pa->version = PROP_AREA_VERSION;
/* reserve root node */
pa->bytes_used = sizeof(prop_bt);
/* plug into the lib property services */
__system_property_area__ = pa; // __system_property_area__全局变量
close(fd);
return 0;
}
static int init_workspace(workspace *w, size_t size){
void *data;
int fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW); // 只读工作区间pa_workspace
if (fd < 0)
return -1;
w->size = size;
w->fd = fd;
return 0;
}
初始化property内存,工作区间完成。
下面开始启动property_service:
static int property_service_init_action(int nargs, char **args){
start_property_service(); // 开始启动property_service
return 0;
}
void start_property_service(void){
int fd;
// 依次加载系统属性文件"/system/build.prop", "/system/default.prop"
load_properties_from_file(PROP_PATH_SYSTEM_BUILD);
load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);
load_override_properties(); // 如果存在"/data/local.prop",则会覆盖已有属性
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties(); // 加载persistent属性,读取/data/property/目录
fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0); // 创建socket
if(fd < 0) return;
fcntl(fd, F_SETFD, FD_CLOEXEC);
fcntl(fd, F_SETFL, O_NONBLOCK);
listen(fd, 8); // 进入监听
property_set_fd = fd;
}
加载属性文件:
static void load_properties_from_file(const char *fn){
char *data;
unsigned sz;
data = read_file(fn, &sz);
if(data != 0) {
load_properties(data); // 读取属性文件后,调用property_set设置属性值
free(data);
}
}
persist开头的属性会做特殊处理,设置时除了设置属性,还会写到/data/property目录下,需要设置后重启还能生效的属性需要以persist方式保存。例如:art和dvm切换,persist.sys.dalvik.vm.lib
// 加载persistent属性
load_persistent_properties
// 设置persistent属性
int property_set(const char *name, const char *value){
if (persistent_properties_loaded &&
strncmp("persist.", name, strlen("persist.")) == 0) {
char bootmode[PROP_VALUE_MAX];
ret = property_get("ro.bootmode", bootmode);
if (ret <= 0 || (strcmp(bootmode, "charger") != 0)) //do not write prop while charger mode
/*
* Don't write properties to disk until after we have read all default properties
* to prevent them from being overwritten by default values.
*/
write_persistent_property(name, value); // 写persistent属性到/data/property
}
return 0;
}
到这里,property_service就启动了。