Use /persist as Qualcomm time fix source during early boot

* /persist can be mounted early while TWRP is parsing the fstab so
  as soon as the partition is parsed, mount and adjust the time
  accordingly.

* Store a backup settings file on /persist. Having a 2nd copy of
  the settings file in the /persist partition allows for early
  reading of the file and adjust timezone and brightness to user
  preference while still on TWRP splash.

* Add the qcom ats time offset in TWRP settings file and use it
  if no better ats file is found. This will also allow devices
  with a persist partition, but no ats files in it, to adjust
  the time offset during early boot.

* Use /persist/time/ as Qualcomm time fix source, based on
  Xuefer <xuefer@gmail.com> patch:
  https://gerrit.omnirom.org/c/27265/
  https://gerrit.omnirom.org/c/24384/

Change-Id: I6c21538eec58d87edfb639d9ce3871f33b886c1d
diff --git a/twrp-functions.cpp b/twrp-functions.cpp
index 5df44c6..b7bcebe 100644
--- a/twrp-functions.cpp
+++ b/twrp-functions.cpp
@@ -881,9 +881,12 @@
 	}
 }
 
-void TWFunc::Fixup_Time_On_Boot()
+void TWFunc::Fixup_Time_On_Boot(const string& time_paths /* = "" */)
 {
 #ifdef QCOM_RTC_FIX
+	static bool fixed = false;
+	if (fixed)
+		return;
 
 	LOGINFO("TWFunc::Fixup_Time: Pre-fix date and time: %s\n", TWFunc::Get_Current_Date().c_str());
 
@@ -904,6 +907,7 @@
 		if (tv.tv_sec > 1405209403) { // Anything older then 12 Jul 2014 23:56:43 GMT will do nicely thank you ;)
 
 			LOGINFO("TWFunc::Fixup_Time: Date and time corrected: %s\n", TWFunc::Get_Current_Date().c_str());
+			fixed = true;
 			return;
 
 		}
@@ -925,22 +929,28 @@
 	// Like, ats_1 is for modem and ats_2 is for TOD (time of day?).
 	// Look at file time_genoff.h in CodeAurora, qcom-opensource/time-services
 
-	static const char *paths[] = { "/data/system/time/", "/data/time/"  };
+	std::vector<std::string> paths; // space separated list of paths
+	if (time_paths.empty()) {
+		paths = Split_String("/data/system/time/ /data/time/", " ");
+		if (!PartitionManager.Mount_By_Path("/data", false))
+			return;
+	} else {
+		// When specific path(s) are used, Fixup_Time needs those
+		// partitions to already be mounted!
+		paths = Split_String(time_paths, " ");
+	}
 
 	FILE *f;
 	offset = 0;
 	struct dirent *dt;
 	std::string ats_path;
 
-	if (!PartitionManager.Mount_By_Path("/data", false))
-		return;
-
 	// Prefer ats_2, it seems to be the one we want according to logcat on hammerhead
 	// - it is the one for ATS_TOD (time of day?).
 	// However, I never saw a device where the offset differs between ats files.
-	for (size_t i = 0; i < (sizeof(paths)/sizeof(paths[0])); ++i)
+	for (size_t i = 0; i < paths.size(); ++i)
 	{
-		DIR *d = opendir(paths[i]);
+		DIR *d = opendir(paths[i].c_str());
 		if (!d)
 			continue;
 
@@ -950,34 +960,38 @@
 				continue;
 
 			if (ats_path.empty() || strcmp(dt->d_name, "ats_2") == 0)
-				ats_path = std::string(paths[i]).append(dt->d_name);
+				ats_path = paths[i] + dt->d_name;
 		}
 
 		closedir(d);
 	}
 
-	if (ats_path.empty())
-	{
+	if (ats_path.empty()) {
 		LOGINFO("TWFunc::Fixup_Time: no ats files found, leaving untouched!\n");
-		return;
-	}
-
-	f = fopen(ats_path.c_str(), "r");
-	if (!f)
-	{
+	} else if ((f = fopen(ats_path.c_str(), "r")) == NULL) {
 		LOGINFO("TWFunc::Fixup_Time: failed to open file %s\n", ats_path.c_str());
-		return;
-	}
-
-	if (fread(&offset, sizeof(offset), 1, f) != 1)
-	{
+	} else if (fread(&offset, sizeof(offset), 1, f) != 1) {
 		LOGINFO("TWFunc::Fixup_Time: failed load uint64 from file %s\n", ats_path.c_str());
 		fclose(f);
-		return;
-	}
-	fclose(f);
+	} else {
+		fclose(f);
 
-	LOGINFO("TWFunc::Fixup_Time: Setting time offset from file %s, offset %llu\n", ats_path.c_str(), offset);
+		LOGINFO("TWFunc::Fixup_Time: Setting time offset from file %s, offset %llu\n", ats_path.c_str(), (unsigned long long) offset);
+		DataManager::SetValue("tw_qcom_ats_offset", (unsigned long long) offset, 1);
+		fixed = true;
+	}
+
+	if (!fixed) {
+		// Failed to get offset from ats file, check twrp settings
+		unsigned long long value;
+		if (DataManager::GetValue("tw_qcom_ats_offset", value) < 0) {
+			return;
+		} else {
+			offset = (uint64_t) value;
+			LOGINFO("TWFunc::Fixup_Time: Setting time offset from twrp setting file, offset %llu\n", (unsigned long long) offset);
+			// Do not consider the settings file as a definitive answer, keep fixed=false so next run will try ats files again
+		}
+	}
 
 	gettimeofday(&tv, NULL);
 
@@ -993,7 +1007,6 @@
 	settimeofday(&tv, NULL);
 
 	LOGINFO("TWFunc::Fixup_Time: Date and time corrected: %s\n", TWFunc::Get_Current_Date().c_str());
-
 #endif
 }