Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

clock_get_time/mach_absolute_time stops updating when device goes to sleep on iOS 7

My application uses mach_absolute_time to calculate the ticks since the last touch event and logs the user out if it surpasses an idle time limit of 10 minutes.

This all works fine on iOS 6, but I noticed that it was not behaving correctly on iOS 7. Specifically, when the iOS 7 device is unplugged (on battery), it seems that the device stops incrementing its ticks once it goes to sleep following this line in the console (this happens after about 5 minutes of inactivity):

powerd[47] : Sleep: Using BATT (Charge:99%)

Therefore, when I wake the device up after 10 minutes, and calculate the ticks using mach_absolute_time, the difference shows to be only 5 minutes (when in reality, 10 minutes have passed).

Strangely enough, all works properly and the ticks continue to run when the device is plugged in to a power source. It never shows that the device is going to sleep on the console log when it is plugged in (although the screen does turn off and the behavior is the same visually as when unplugged).

I've tried this using clock_get_time as well, and I'm facing the same issue there.

Is there something I can do in iOS 7 to keep Mach absolute time ticking when the device goes to sleep? I don't want to use [[NSDate date] timeIntervalSince1970] as users are able to manipulate the system time and bypass this.

Thanks for any insights.

like image 927
Jay Avatar asked Nov 01 '22 11:11

Jay


2 Answers

Turns out the default behavior of mach_absolute_time() is to stop ticking once the device goes to sleep. On iOS 6 I was able to extend the time till suspension by 10 minutes when the app was put into the background using beginBackgroundTaskWithExpirationHandler. In iOS 7, however, the maximum time allowed for this has been capped at 3 minutes (found this out by calling backgroundTimeRemaining). This is why I was seeing the clock stop on iOS 7, but not on iOS 6.

Stumbled upon this answer today, which seems promising.

- (time_t)uptime {
    struct timeval boottime;
    int mib[2] = {CTL_KERN, KERN_BOOTTIME};
    size_t size = sizeof(boottime);
    time_t now;
    time_t uptime = -1;
    (void)time(&now);
    if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec != 0) {
        uptime = now - boottime.tv_sec;
    }
    return uptime;
}

time() carries on incrementing while the device is asleep, but of course can be manipulated by the operating system or user. However, the Kernel boottime (a timestamp of when the system last booted) also changes when the system clock is changed, therefore even though both these values are not fixed, the offset between them is.

like image 81
Jay Avatar answered Nov 12 '22 11:11

Jay


You can nowadays use clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW) which includes the time spent asleep. In Swift:

import Foundation

let elapsed_time_nanos = clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW)

I can't find documentation for that function on the Apple website, but the docs for mach_continuous_time mention it.

like image 24
robinst Avatar answered Nov 12 '22 10:11

robinst