How can I detect whether the iphone has been rebooted since last time app started - iphone

I'd like to detect from within my app whether the iPhone has been rebooted since last time my app was started. I need to do this because my app uses the timer since last system reboot to clock a user's time and I want to detect reboot so I can invalidate the time.
Is there anywhere I could extract the information from the system console log like reboot , crashes ? The organizer in xcode can access it , maybe I can too.
If not , can you think of other ways to get this information?

This seems like it would work:
get the time since last reboot, and for this example, let's store it in a variable called 'tslr' (duration in milliseconds I guess, BTW, how do you get that?)
get the current time, store it in variable 'ct' for example
compute the last reboot time (let's call it 'lr'), we have: lr = ct - tslr
store 'lr'
Next time your application gets started, load the previous value for 'lr', compute the new one, and if they differ, you have detected a reboot (you'll probably have to tolerate a small difference there... a couple milliseconds perhaps).
I think it would be pretty tough to fool that... the user would have to tamper their phone time very precisely, and they would have to start your application at a very precise moment on top of that, exactly when the new 'lr' would be identical to the previous one... pretty tough to do, the probability of them being able to do that is very close to 0 I think. And you don't need any internet connection to do that...
The new 'lr' would be identical to the previous one in the following cases only:
phone was not rebooted, and time was not changed
time was tampered with, AND the user managed to start your application at the precise millisecond to fool your algorithm (chances of that happening more than ultraslim)

// Returns true if device has rebooted since last time
private func deviceRebootedSinceLastTime() -> Bool {
let userDefaults = NSUserDefaults.standardUserDefaults()
let systemUptime = NSProcessInfo.processInfo().systemUptime;
let timeNow = NSDate().timeIntervalSince1970
let dateOfLastReboot = NSDate(timeIntervalSince1970: timeNow-systemUptime)
var didDeviceRebootSinceLastTime = false
if let storedDateOfLastReboot:NSDate = userDefaults.objectForKey("deviceLastRebootDate") as? NSDate {
if Int(dateOfLastReboot.timeIntervalSinceDate(storedDateOfLastReboot)) < 1 { //
print("Reboot time didn't change - date: \(dateOfLastReboot)");
}
else {
print("Reboot time has changed - from: \(storedDateOfLastReboot) to \(dateOfLastReboot)");
didDeviceRebootSinceLastTime = true
}
}
else {
print("Reboot time is saved for the first time")
didDeviceRebootSinceLastTime = true // first time we save value
}
userDefaults.setObject(dateOfLastReboot, forKey: "deviceLastRebootDate")
userDefaults.synchronize() // don't forget this!!!
return didDeviceRebootSinceLastTime;
}

Zoran's answer is the right way to go; it's the closest you are going to get without a network connection. (neither the cellular subsystem, nor the syslog are accessible for security reasons)
If you are looking to prevent malicious users from generating fake time data, have some central server (or trusted local server for enterprise deployments) track time-related events for you.

Get and save the time either from the iPhone or from NIST and the current runtime from the BSD uptime function. For NIST time see How can I get the real time in iPhone, not the time set by user in Settings?
When you want to check for a reboot get new values of these, compute the elapsed time for each and compare the elapsed times. Based on the difference you should be able to determine a reboot.

Here is one I made. It takes the current time in GMT and the time since last reboot to extrapolate a date for when the device was last restarted. Then it keeps track of this date in memory using NSUserDefaults. Enjoy!
Note: Since you want to check this since last time app was started, you need to make sure you call the method anytime the app is started. The easiest way would be to call the method below in +(void)initialize { and then also whenever you need to check it manually
#define nowInSeconds CFAbsoluteTimeGetCurrent()//since Jan 1 2001 00:00:00 GMT
#define secondsSinceDeviceRestart ((int)round([[NSProcessInfo processInfo] systemUptime]))
#define storage [NSUserDefaults standardUserDefaults]
#define DISTANCE(__valueOne, __valueTwo) ((((__valueOne)-(__valueTwo))>=0)?((__valueOne)-(__valueTwo)):((__valueTwo)-(__valueOne)))
+(BOOL)didDeviceReset {
static BOOL didDeviceReset;
static dispatch_once_t onceToken;
int currentRestartDate = nowInSeconds-secondsSinceDeviceRestart;
int previousRestartDate = (int)[((NSNumber *)[storage objectForKey:#"previousRestartDate"]) integerValue];
int dateVarianceThreshold = 10;
dispatch_once(&onceToken, ^{
if (!previousRestartDate || DISTANCE(currentRestartDate, previousRestartDate) > dateVarianceThreshold) {
didDeviceReset = YES;
} else {
didDeviceReset = NO;
}
});
[storage setObject:#(currentRestartDate) forKey:#"previousRestartDate"];
[storage synchronize];
return didDeviceReset;
}

Related

How to properly measure elapsed time in background in Swift

I have this two functions that measure the elapsed time when the phone is locked or the app is in background:
func saveTimeInBackground(){
startMeasureTime = Int(Date.timeIntervalSinceReferenceDate)
}
func timeOnAppActivated(){
stopMeasureTime = Int(Date.timeIntervalSinceReferenceDate)
elapsedTime = stopMeasureTime - startMeasureTime
seconds = seconds - elapsedTime + 2
if seconds > 0 {
timerLbl.text = "time: \(seconds)"
} else {
seconds = 0
timerLbl.text = "time: \(seconds)"
}
}
and then in the viewDidLoad() i have observers that are trigger the functions when the app becomes active/inactive:
NotificationCenter.default.addObserver(self, selector: #selector(saveTimeInBackground), name: Notification.Name.UIApplicationWillResignActive, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(timeOnAppActivated), name: Notification.Name.UIApplicationDidBecomeActive, object: nil)
The problem is that when the app becomes active there are 2 seconds (approximately) of difference so i've added 2 seconds and it seems to work fine, but only if the elapsed time is > 15 seconds.
If i lock the phone and immediately unlock it the there are like 5 or more seconds that are missing. For example, if there are 50 seconds left, when i lock and immediately unlock it there are like 42 seconds left.
Can anyone please explain, what i am doing wrong?
Edit: The logic of the app is this:
It starts a match between 2 players with 60 seconds for a game. The problem is that when one of the players locks the phone the app stop to measure the time. This way if the player1 has 10 seconds left to make a move, the player2 still has 50 seconds left. I'm looking for a reliable way to calculate the time even if the player locks the phone or put the app in background.
Edit 2: I think i figured out what the problem is: I think the issue has to do with the fact that the “seconds” are Int, and the Date not and when it gets converted it’s rounded up. I didn't tested it, but when i ahve the solution i'll post the answer. Thanks all for your time!
You're relying on exact timing of notifications that aren't guaranteed to have any exact timing. There's no guarantee about when, exactly, either of those notifications will arrive, and there's nothing you can do about that. Even your two-second fix is, as you say, approximate. It'll probably be different on different models of iPhone or even at different times on the same iPhone, depending how busy iOS is when you check.
What's more, when you go into the background, you can't be certain that you'll stay there. Once in the background, iOS might decide to terminate your app at any time.
I'm not sure what the goal is here but I think you'll need to reconsider what you want to do and see if there's some other approach. Your current two-second hack will, at best, spawn a bunch of other hacks (like the 15 second threshold you mention) without ever being especially accurate. And then it'll probably all break in the next iOS update when some iOS change causes the timing to change.
I would use Date object to track game time.
func gameStart() {
gameStartDate = Date()
}
func timeOnAppActivated() {
let secondsLeft = 60 - abs(gameStartDate?.timeIntervalSinceNow ?? 0)
if secondsLeft > 0 {
timerLbl.text = "time: \(secondsLeft)"
} else {
timerLbl.text = "time: 0"
}
}
Ok, like I mention in the edit 2 of the question:
The first issue was because "seconds" is a Int and then it almost always gains or lose when converting it from Double.
But the main problem was that i had to invalidate the timer when the app enter in background and i didn't.
So now with invalidating the timer when the app gets the notification that will enter background and then starting it when it enter foreground everything works fine.
To test this properly call those methods on button click. It may be coz of delay in releasing some resources in background.

How do I reset a variable at the start of each day?

I have a variable that keeps track of user statistic I want to reset at the beginning of each day. How can I do that?
Since the application is not allowed to run in the background, it seems I will have to do the check every time the application is active but I don't know how to reset the variable I have only once. This is the function I wanted to use:
let beginingOfDay = NSCalendar.currentCalendar().startOfDayForDate(NSDate())
func resetCurrentTime(){
// Date comparision to compare current date and begining of the day.
let dateComparisionResult:NSComparisonResult = NSDate().compare(beginingOfDay)
if dateComparisionResult == NSComparisonResult.OrderedDescending || dateComparisionResult == NSComparisonResult.OrderedSame {
// Current date is greater or equal to end date.
currentTime = 0 //reset the time tracker
}
}
I wanted to use this function to check when the application is launched but the problem is that the application could be launched many time a day. How I can reset my variable only once at the beginning of a day if the user is using the application or when the application becomes active or is launched for the first time that day?
Thanks
You can store in the user defaults this value.
So the flow is the following:
When the app is launched or became active you check whether the value of the variable in the user defaults is the same as the current day (e.g. 25/07/2016), then do nothing.
If the value is different, then you update the value in the user defaults with the current day.
If the app is running and the date is changed, you can update the value of your variable by subscribing to this notification:
UIApplicationSignificantTimeChangeNotification

How to get NSTimeInterval value from last boot

I need to get NSTimeInterval value from last device boot. I found CACurrentMediaTime() which suits this task, but in my app I am not using Core Animation and I don't think that this is the best way to include this framework just to get this function. Is there another way to get time in seconds from last boot more elegant way?
The NSTimeInterval value since the last system restart can be acquired more directly via the following Foundation object and method:
[[NSProcessInfo processInfo] systemUptime]
The fastest low-level method is to read system uptime from processor using mach_absolute_time()
#include <mach/mach_time.h>
int systemUptime()
{
static float timebase_ratio;
if (timebase_ratio == 0) {
mach_timebase_info_data_t s_timebase_info;
(void) mach_timebase_info(&s_timebase_info);
timebase_ratio = (float)s_timebase_info.numer / s_timebase_info.denom;
}
return (int)(timebase_ratio * mach_absolute_time() / 1000000000);
}
Note that timebase_ratio is different for processors. For example, on macbook it equals 1 whereas on iPhone 5 it equals 125/3 (~40).
Try a C system call, times(3) is supposed to return uptime.
On MacOSX, uptime also returns such. So there has to be a way though that as well.

IPhone: different system timers?

I have been using mach_absolute_time() for all my timing functions so far. calculating how long between frames etc.
I now want to get the exact time touch input events happen using event.timestamp in the touch callbacks.
the problem is these two seem to use completely different timers. sure, you can get them both in seconds, but their origins are different and seemingly random...
is there any way to sync the two different timers?
or is there anyway to get access to the same timer that the touch input uses to generate that timestamp property? otherwise its next to useless.
Had some trouble with this myself. There isn't a lot of good documentation, so I went with experimentation. Here's what I was able to determine:
mach_absolute_time depends on the processor of the device. It returns ticks since the device was last rebooted (otherwise known as uptime). In order to get it in a human readable form, you have to modify it by the result from mach_timebase_info (a ratio), which will return billionth of seconds (or nanoseconds). To make this more usable I use a function like the one below:
#include <mach/mach_time.h>
int getUptimeInMilliseconds()
{
static const int64_t kOneMillion = 1000 * 1000;
static mach_timebase_info_data_t s_timebase_info;
if (s_timebase_info.denom == 0) {
(void) mach_timebase_info(&s_timebase_info);
}
// mach_absolute_time() returns billionth of seconds,
// so divide by one million to get milliseconds
return (int)((mach_absolute_time() * s_timebase_info.numer) / (kOneMillion * s_timebase_info.denom));
}
Get the initial difference between two i.e
what is returned by mach_absolute_time() initally when your application starts and also get the event.timestamp initially at the same time...
store the difference... it would remain same through out the time your application runs.. so you can use this time difference to convert one to another...
How about CFAbsoluteTimeGetCurrent?

Is it possible to get the atomic clock timestamp from the iphone GPS?

I'm looking for a reliable way to get the time. It can't be tampered with and it needs to work offline. So no internet time , no user time setup in settings and no BSD uptime time since last reboot. I was wondering since GPS works using atomic clock, whether I could access that information.
Thank you
This works to get the GPS time:
#import <CoreLocation/CoreLocation.h>
CLLocation* gps = [[CLLocation alloc]
initWithLatitude:(CLLocationDegrees) 0.0
longitude:(CLLocationDegrees) 0.0];
NSDate* now = gps.timestamp;
It doesn't seem to be tamper-proof though.
I tried this code on an iPhone 4 in airplane mode (iOS 6.1), and even then it gives a time all right. But unfortunately this time seems to change with the system clock. Ugh.
Funny thing that I found (still in airplane mode) is that if you tamper with the system clock (after turning to off Time & Date's Set Automatically), and then turn Set Automatically back to on, the machine restores the real (original) time without a hitch. this works even after cycling the phone's power. So it seems that there is something like a tamper-proof time the device maintains internally. But how to access this?
P.S. A discussion of this from 2010. The author of the penultimate comment tried this in a fallout shelter: so it's clear the phone is not getting the pristine time from any external source.
Addendum, July 2013
Found a few more posts (here, here and here) about another kind of time measure: system kernel boot time. It's accessed through a call something like this: sysctlbyname("kern.boottime", &boottime, &size, NULL, 0);. Unfortunately it too changes with the user-adjusted data and time, even without reboot. Another function gettimeofday() is similarly dependent on user-defined time.
NSDate and it's CF counterpart are all based on the user controllable time, and thereby aren't tamper proof.
As far as I know, there is no open API for either GPS time or carrier time directly. However, you can check the mach_absolute_time to get untampered time since last boot up, and perhaps use it to at least be aware of how much time has passed since the app has been awoken (without having the potential for that time to be tampered with while the app is running).
mach_absolute_time depends on the processor of the device. It returns ticks since the device was last rebooted (otherwise known as uptime). In order to get it in a human readable form, you have to modify it by the result from mach_timebase_info (a ratio), which will return billionth of seconds (or nanoseconds). To make this more usable I use a function like the one below:
#include <mach/mach_time.h>
int getUptimeInMilliseconds()
{
static const int64_t kOneMillion = 1000 * 1000;
static mach_timebase_info_data_t s_timebase_info;
if (s_timebase_info.denom == 0) {
(void) mach_timebase_info(&s_timebase_info);
}
// mach_absolute_time() returns billionth of seconds,
// so divide by one million to get milliseconds
return (int)((mach_absolute_time() * s_timebase_info.numer) / (kOneMillion * s_timebase_info.denom));
}
Even if you can get hold of the time from GPS you should be aware that GPS time is not quite the same as UTC. The GPS receiver in the iPhone might take care of that for you though.
This gets you the current date and time:
NSDate *now = [NSDate date];
This will be as reliable as you can get. The internal clock on the iPhone will be updated when it can get access to an NTP server. If the phone uses GPS as a time sync source it'll also be used to update the same system-wide clock which is accessible via the above method.
The CoreFoundation equivalent is something like:
CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
Which returns the CoreFoundation equivalent of the normal UNIX seconds-since-epoch timestamp.
The gold standard of timekeeping are the various government time observatories in the U.S. and worldwide. They provide Atomic time. That is used world wide. Apple should be using that. If the want to sync w/ the cell towers, there should be an Alternate internal time. If the tower or GPS system malfunctions all are left with incorrect time.