이전에 ro 프로퍼티 값에 대해서 알아봤는데, 이번에는 persist 값에 대해 알아 보도록 하겠습니다.
persist property 란
persist는 지워지지 않고 계속 유지 되는 값을 의미합니다. 일반적인 property는 한번 write후에 재부팅시 이전에 씌여졌던값은 지워지게 됩니다. 그래서 안드로이드에서 특별한 property를 만들어 두었습니다.
사용법
프로퍼티 앞에 persist. 을 붙여주면 됩니다. 그러면 해당값을 특별한 영역에 넣어 두었다가 부팅시 다시 읽어 들여서 항상 값을 저장 할 수 있는 형태을 취하게 됩니다.
저장하는 코드는 어디에?
기본적인 코드는 init process 소스에 있습니다. write시 아래 소스 134 line에서 /data/property 폴더에 property 이름으로 해당 내용을 저장하게 됩니다. 124 line에서 temp이름을 만드는 이유는 이미 존재하는 경우 write중에 전원 off시 기존 property 값이 문제가 생기게 되기 때문에 rename 하는 형태로 코드를 많이 작성 합니다.
/system/core/init/property_service.cpp
166uint32_t property_set(const std::string& name, const std::string& value) { 167 size_t valuelen = value.size(); 168 204 205 // Don't write properties to disk until after we have read all default 206 // properties to prevent them from being overwritten by default values. 207 if (persistent_properties_loaded && android::base::StartsWith(name, "persist.")) { 208 write_persistent_property(name.c_str(), value.c_str()); 209 } 210 property_changed(name, value); 211 return PROP_SUCCESS; 212}
61#define PERSISTENT_PROPERTY_DIR "/data/property"
118static void write_persistent_property(const char *name, const char *value) 119{ 120 char tempPath[PATH_MAX]; 121 char path[PATH_MAX]; 122 int fd; 123 124 snprintf(tempPath, sizeof(tempPath), "%s/.temp.XXXXXX", PERSISTENT_PROPERTY_DIR); 125 fd = mkstemp(tempPath); 126 if (fd < 0) { 127 PLOG(ERROR) << "Unable to write persistent property to temp file " << tempPath; 128 return; 129 } 130 write(fd, value, strlen(value)); 131 fsync(fd); 132 close(fd); 133 134 snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name); 135 if (rename(tempPath, path)) { 136 PLOG(ERROR) << "Unable to rename persistent property file " << tempPath << " to " << path; 137 unlink(tempPath); 138 } 139} 140
Load는 언제 어디에서?
부팅시 load를 하게되는 위치는 rc파일에서 하게 됩니다. late-int에서 load_persist_props_action -> load_persist_props 순으로 호출하게 됩니다.
/system/core/rootdir/init.rc
259on late-init
283 # Load persist properties and override properties (if enabled) from /data. 284 trigger load_persist_props_action
249on load_persist_props_action 250 load_persist_props 251 start logd 252 start logd-reinit
해당 코드는 do_load_persist_props() 함수를 호출하게되며 load_persist_props() 함수를 호출하게 됩니다.
/system/core/init/ | ||
H A D | property_service.h | 32 void load_persist_props(void); |
H A D | builtins.cpp | 769 load_persist_props(); 868 {"load_persist_props", {0, 0, do_load_persist_props}}, |
/system/core/init/property_service.cpp
620void load_persist_props(void) { 621 load_override_properties(); 622 /* Read persistent properties after all default values have been loaded. */ 623 load_persistent_properties(); 624 property_set("ro.persistent_properties.ready", "true"); 625} 626
/data/property 폴더를 열어서 readdir 을하여 이름이 persist. 로 시작하는 d_name이 존재하는지 확인해서 일치하면 568 line에서 읽어서 571 line에 property set을 하게 됩니다.
/system/core/init/property_service.cpp
524static void load_persistent_properties() { 525 persistent_properties_loaded = 1; 526 527 std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(PERSISTENT_PROPERTY_DIR), closedir); 528 if (!dir) { 529 PLOG(ERROR) << "Unable to open persistent property directory \"" 530 << PERSISTENT_PROPERTY_DIR << "\""; 531 return; 532 } 533 534 struct dirent* entry; 535 while ((entry = readdir(dir.get())) != NULL) { 536 if (strncmp("persist.", entry->d_name, strlen("persist."))) { 537 continue; 538 } 539 if (entry->d_type != DT_REG) { 540 continue; 541 } 542 543 // Open the file and read the property value. 544 int fd = openat(dirfd(dir.get()), entry->d_name, O_RDONLY | O_NOFOLLOW); 545 if (fd == -1) { 546 PLOG(ERROR) << "Unable to open persistent property file \"" << entry->d_name << "\""; 547 continue; 548 } 549 550 struct stat sb; 551 if (fstat(fd, &sb) == -1) { 552 PLOG(ERROR) << "fstat on property file \"" << entry->d_name << "\" failed"; 553 close(fd); 554 continue; 555 } 556 557 // File must not be accessible to others, be owned by root/root, and 558 // not be a hard link to any other file. 559 if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0) || sb.st_uid != 0 || sb.st_gid != 0 || sb.st_nlink != 1) { 560 PLOG(ERROR) << "skipping insecure property file " << entry->d_name 561 << " (uid=" << sb.st_uid << " gid=" << sb.st_gid 562 << " nlink=" << sb.st_nlink << " mode=" << std::oct << sb.st_mode << ")"; 563 close(fd); 564 continue; 565 } 566 567 char value[PROP_VALUE_MAX]; 568 int length = read(fd, value, sizeof(value) - 1); 569 if (length >= 0) { 570 value[length] = 0; 571 property_set(entry->d_name, value); 572 } else { 573 PLOG(ERROR) << "Unable to read persistent property file " << entry->d_name; 574 } 575 close(fd); 576 } 577}
댓글 없음:
댓글 쓰기