OSDN Git Service

Support use local time for RTC
authorMa Jian <majian@jidemail.com>
Sun, 12 Jun 2016 09:34:25 +0000 (17:34 +0800)
committerChih-Wei Huang <cwhuang@linux.org.tw>
Sat, 6 May 2017 14:54:43 +0000 (22:54 +0800)
When default timezone isn't UTC, there will no persist.sys.timezone
under /data/property/, so init won't get the default timezone for
setting time from rtc.

This change adds a fallback to read the property when the persist file
does not exists.

Notice, the default property of persist.sys.timezone should be set in
/default.prop instead of /system/build.prop

NO_REF_TASK
Tested: set default timezone with Asia/Shanghai, make sure bios time
is correct in local time, reboot to android, the local time should
be correct.

Change-Id: Ifbd20cb3710f833ab65852b4e5d51e38cc7c2d79

init/builtins.cpp

index 59fc987..f918c59 100644 (file)
@@ -785,13 +785,96 @@ static int do_rmdir(const std::vector<std::string>& args) {
     return rmdir(args[1].c_str());
 }
 
+// read persist property from /data/property directly, because it maybe has not loaded
+// if the file not found, try to call property_get, the default value could be saved
+// into /default.prop
+static std::string persist_property_get(const char *name)
+{
+    const char *filename_template = "/data/property/%s";
+    size_t max_file_name_len = strlen(filename_template) + PROP_NAME_MAX;
+    char filename[max_file_name_len];
+    snprintf(filename, max_file_name_len, filename_template, name);
+
+    if (access(filename, 0) == 0) {
+        char *line = NULL;
+        size_t len;
+        FILE *fp = fopen(filename, "r+");
+        if (fp == NULL) {
+            ERROR("failed to read file for property:%s\n", filename);
+            return 0;
+        }
+
+        std::string result;
+        if (getline(&line, &len, fp) == -1) {
+            len = 0;
+        } else {
+            for (len = 0; *(line+len) != '\n' && *(line+len) != 0; len++);
+            *(line + len) = '\0';
+            result = line;
+            free(line);
+        }
+        fclose(fp);
+        return result;
+    }
+
+    return property_get(name);
+}
+
 static int do_sysclktz(const std::vector<std::string>& args) {
     struct timezone tz;
+    struct timeval tv;
+    struct tm tm;
+    time_t t;
 
     memset(&tz, 0, sizeof(tz));
-    tz.tz_minuteswest = std::stoi(args[1]);
-    if (settimeofday(NULL, &tz))
+    memset(&tv, 0, sizeof(tv));
+    memset(&tm, 0, sizeof(tm));
+
+    INFO("sysclktz: the arg %s is ignored, only persist.rtc_local_time matters\n", args[1].c_str());
+
+    if (gettimeofday(&tv, NULL)) {
+        ERROR("sysclktz: failed to call gettimeofday");
         return -1;
+    }
+
+    if (persist_property_get("persist.rtc_local_time") == "1") {
+        /* Notify kernel that hwtime use local time */
+        write_file("/sys/class/misc/alarm/rtc_local_time", "1");
+        /*
+         * If ro.hwtime.mode is local, set system time
+         * and saved system zone in case of network not
+         * available and auto syncing time not available.
+         */
+
+        std::string time_zone = persist_property_get("persist.sys.timezone");
+        if (time_zone.empty()) {
+            INFO("sysclktz: persist.sys.timezone not found\n");
+            tz.tz_minuteswest = 0;
+        } else {
+            const char *timezone_prop = time_zone.c_str();
+            INFO("sysclktz: persist.sys.timezone: %s\n", timezone_prop);
+            // localtime_r need the property, we need to set it
+            property_set("persist.sys.timezone", timezone_prop);
+            t = tv.tv_sec;
+            localtime_r(&t, &tm);
+            tz.tz_minuteswest = -(tm.tm_gmtoff / 60);
+            INFO("sysclktz: tz.tz_minuteswest: %d\n", tz.tz_minuteswest);
+        }
+
+        /*
+         * At this moment, system time should be local
+         * time too, set it back to utc which linux required.
+         */
+        tv.tv_sec += tz.tz_minuteswest * 60;
+        if (settimeofday(&tv, &tz)) {
+            ERROR("sysclktz: failed to call settimeofdays\n");
+            return -1;
+        }
+    } else {
+        tz.tz_minuteswest = std::stoi(args[1]);
+        return settimeofday(NULL, &tz);
+    }
+
     return 0;
 }