Search code examples
iostimeunix-timestamp

Can iOS boot time drift?


I'm using this code to determine when my iOS device last rebooted:

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;

I'm seeing some anomalies with this time. In particular, I save the long and days and weeks later check the saved long agains the value returned by the above code.

I'm not sure, but I think I'm seeing some drift. This doesn't make any sense to me. I'm not converting to NSDate to prevent drift. I would think that boot time is record by the kernel when it boots and isn't computed again, it is just stored. But could iOS be saving boot time as an NSDate, with any inherent drift problems with that?


Solution

  • While the iOS Kernel is closed-source, it's reasonable to assume most of it is the same as the OSX Kernel, which is open-source.

    Within osfmk/kern/clock.c there is the function:

    /*
     *  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);
    }
    

    and clock_boottime is declared as:

    static uint64_t     clock_boottime;             /* Seconds boottime epoch */
    

    and finally the comment to this function shows that it can, indeed, change:

    /*
     *  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)
    {
        ...
    

    Update to answer query from OP

    I am not certain about how often clock_set_calendar_microtime() is called, as I am not familiar with the inner workings of the kernel; however it adjusts the clock_boottime value and the clock_bootime value is initialized in clock_initialize_calendar(), so I would say it can be called more than once. I have been unable to find any call to it using:

    $ find . -type f -exec grep -l clock_set_calendar_microtime {} \;