我正在使用此代码来确定我的iOS设备上次重启的时间:
int mib[MIB_SIZE];
size_t size;
struct timeval boottime;
mib[0] = CTL_KERN;
mib[1] = KERN_BOOTTIME;
size = sizeof(boottime);
if (sysctl(mib, MIB_SIZE, &boottime, &size, NULL, 0) != -1) {
return boottime.tv_sec;
}
return 0;
这次我看到了一些异常现象。特别是,我保存了很长时间,几天和几周之后再检查保存的long longs上面代码返回的值。
我不确定,但我想我看到了一些漂移。这对我没有任何意义。我没有转换到NSDate以防止漂移。我认为引导时间是内核在引导时记录的,并且不再计算,它只是存储。但iOS可以将启动时间作为NSDate来保存,并且有任何固有的漂移问题吗?
虽然iOS内核是封闭源代码,但可以合理地假设其大部分内容与OSX内核相同,即open-source。
在osfmk/kern/clock.c
内有功能:
/*
* clock_get_boottime_nanotime:
*
* Return the boottime, used by sysctl.
*/
void
clock_get_boottime_nanotime(
clock_sec_t *secs,
clock_nsec_t *nanosecs)
{
spl_t s;
s = splclock();
clock_lock();
*secs = (clock_sec_t)clock_boottime;
*nanosecs = 0;
clock_unlock();
splx(s);
}
和clock_boottime
宣布为:
static uint64_t clock_boottime; /* Seconds boottime epoch */
最后对这个函数的评论表明它确实可以改变:
/*
* clock_set_calendar_microtime:
*
* Sets the current calendar value by
* recalculating the epoch and offset
* from the system clock.
*
* Also adjusts the boottime to keep the
* value consistent, writes the new
* calendar value to the platform clock,
* and sends calendar change notifications.
*/
void
clock_set_calendar_microtime(
clock_sec_t secs,
clock_usec_t microsecs)
{
...
更新以回答OP的查询
我不确定调用clock_set_calendar_microtime()
的频率,因为我不熟悉内核的内部工作原理;然而,它调整clock_boottime
值和clock_bootime
值在clock_initialize_calendar()
初始化,所以我会说它可以不止一次调用。我无法使用以下方法找到任何调用:
$ find . -type f -exec grep -l clock_set_calendar_microtime {} \;
我上面的评论......
“根据我的理解,当用户进入设置并手动更改时间时,启动时间会由增量更改为新时间,以保持启动时间和系统时间之间的间隔相等。但它不会”漂移“为它是一个时间戳,只有系统时钟本身漂移。“
我在我的iOS应用程序上运行NTP,并与Google的时间服务器通话。
我给NTP提供了自启动以来的正常运行时间(如果一些恶意的用户开始搞乱系统时间而没有暂停并正确调整...这首先是这个问题的全部要点),然后在正常运行时间之间添加偏移量启动和纪元时间到我的正常运行时间。
inline static struct timeval uptime(void) {
struct timeval before_now, now, after_now;
after_now = since_boot();
do {
before_now = after_now;
gettimeofday(&now, NULL);
after_now = since_boot();
} while (after_now.tv_sec != before_now.tv_sec && after_now.tv_usec != before_now.tv_usec);
struct timeval systemUptime;
systemUptime.tv_sec = now.tv_sec - before_now.tv_sec;
systemUptime.tv_usec = now.tv_usec - before_now.tv_usec;
return systemUptime;
}
我每15分钟与时间服务器同步一次,并且每次都计算偏移漂移(也就是系统时钟漂移)。
static void calculateOffsetDrift(void) {
static dispatch_queue_t offsetDriftQueue = dispatch_queue_create("", DISPATCH_QUEUE_CONCURRENT);
static double lastOffset;
dispatch_barrier_sync(offsetDriftQueue, ^{
double newOffset = networkOffset();
if (lastOffset != 0.0f) printf("offset difference = %f \n", lastOffset - newOffset);
lastOffset = newOffset;
});
}
在我的iPhone Xs Max上,系统时钟通常在15分钟后运行大约30ms。
以下是我刚刚在纽约市使用LTE进行测试的一些数据。
+47.381592 ms
+43.325684 ms
-67.654541 ms
+24.860107 ms
+5.940674 ms
+25.395264 ms
-34.969971 ms