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就啟動了。