2018년 2월 18일 일요일

(안드로이드에서 persist 프로퍼티 값 처리) about android persist property

이전에 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/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}

 

댓글 없음:

댓글 쓰기