I need to measure long elapsed time on Android and there may be device reboots in between.
From what I've understand, System.nanoTime() is resetted every time the device reboot, and System.currentTimeMillis() is unreliable because user can change it.
The only solution that I came up with is to listen to ACTION_SHUTDOWN and BOOT_COMPLETED, use System.currentTimeMillisec() to calculate the elapsed time (user can't change clock time while the device is off, hopefully :) ) and add it to the last System.nanoTime() I had before shutting down.
I honestly don't like this solution because it's very expensive (I need to listen to 2 broadcast events) and inaccurate, but I couldn't figure out any other way to do this.
Any ideas? Also a native solution would be good for me.
You can get around the user changing time by using an internet time server to get the times when you check. There are a couple of ways to do this.
Get it via NTP server
How to get current time from internet in android
How can I get the "network" time, (from the "Automatic" setting called "Use network-provided values"), NOT the time on the phone?
Get it via HTTP header
http://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Responses ( see Date header )
If you simply persist this value then the user can do nothing to mess up your calculation.
Related
I found what was wrong:
So apparently http://www.epochconverter.com/ is makes assumptions of the precision of the input values, and from those assumptions values around 841073068 goes to 1996/1997. I'm not sure what is the assumption that leads to that exact date, but honestly I don't care.
Using the attached debugger I called new Date(System.currentTimeMillis()) and it correctly gave me a 10th Jan-1070 date, meaning the clock is not jumping out of the way like crazy.
Original question:
I'm running a single-board computer with Android for and IoT case (this https://developer.qualcomm.com/hardware/dragonboard-410c). The OS running is the plain vanilla Android supplied by Qualcomm.
Currently I'm testing the reliability of the board to be left executing for long periods at once and I'm seeing some very very weird behavior that I can't find an explanation for.
The board was powered up 10 days ago and it have no access to internet (WiFi is on but no access point setup and no Ethernet). The bluetooth is on and there're iBeacons and Eddystone in the office. Also there are WiFi in the area.
If I go now to Settings -> Date and Time, or check the notification shade or enter the clock app, or the calendar app, I see 10th of January 1970. Which is expected and basically showing for how long the board been running.
The app on it have an always running service, which does some data processing and some disk-logging (for debugging).
From the logs, I can see that System.currentTimeMillis() was returning an expected value when the board was initially powered on. That means, the beginning of the logs indicate an epoch time in January 1970.
But at the end of the logs (and also attaching the debugger on the live process), the value of System.currentTimeMillis() is somewhere in Sep/Oct 1996. Example values: 841073068, 841263234, 841579239
So my question is:
What is happening here?
Why System.currentTimeMillis() value changed and what could have changed it?
Why the Android UI (notification, clock app, settings) still shows me 1970? Where are they getting this value from?
edit:
There's been some confusion on the answers, and I can see my question was lacking the details.
I do not want to measure difference of time. I need an actual time stamp. Those values will be reported with bluetooth LE events via POST to our backend. This "no network" thing is a reliability test that we're running on the board, but we do expect to have network most of the time, and the boards should auto-update their times from network using the normal Android ways.
I'm just trying to understand on the current batch of testing, what went wrong and why.
Well, as you already know, the current system time (System.currentTimeMillis()) can be modified by any process if desired, it's perfectly be possible that it was modified by another process. It's not a reliable method to measure up-time.
I would rater use something like:
SystemClock.uptimeMillis()
Which returns the elapsed time (in milliseconds) since the device booted (not including time spent in deep-sleep).
I would also like to mention that I suspect that Bluetooth has something to do with it, I can imagine that Bluetooth uses the system time for pairing and security just like SSL does (but I'm no expert). GPS could also be a problem as GPS can be used to obtain an UTC time value, but I'm not sure if your board has a GPS module.
Regarding your edit:
Obtaining a valid time-stamp would be quite easy: server time minus the elapsed time reported by your board. But I suggest you either choose to accept the time reported by System.currentTimeMillis() or use the elapsed time instead. At the company I work we also work with embedded Android devices and on our server dashboard we can see both the up-time (up since) and the current device time, but they should not be mixed, at least in my opinion, especially since System.currentTimeMillis() is subject to changes and is affected by summer and winter time.
If you want to measure something, better try System.nanoTime(). Here is difference - https://stackoverflow.com/a/351571/2793494
I need two devices to have exact same time.
I want to use GPS to get time. It can be done on iOS and Android devices.
Can i be sure that they have exact same time in milliseconds?
No you cannot do that easily.
ios overrides the gps time. If a user adds one hour, and disables auto time sync,
the time is then offset. It will not work that way. If auto time sync is enabled it should work.
However you could query via internet the correct time using a time service, and do the same that NTP do. (network time protocoll). However that looks not to easy.
As an intermediate approach, I would check whether the system time relates to the network time. If yes, one can asume that auto time sync is enabled.
I've noticed that System.currentTimeMillis() time is device dependent. If I change the time on the device's clock, this method will return a different answer.
For example: If the real time now is 10:00, and I change the clock on my device to 9:30, then System.currentTimeMillis() will return the 9:30 time (in milliseconds..).
I've also tried this answer and some other answers, but didn't find anything useful.
I should state that my app works mostly offline.
Is there a way to get the real current time (device independent) without external API?
If it were not for the 'offline' part, I'd have suggested to use a time server, but given that your app is offline most of the time that might not be a good solution.
If you don't need the actual time but just a time that cannot be messed with, you can use SystemClock.elapsedRealtime() which gives you the time since the device last booted.
You could also combine time server and SystemClock.elapsedRealtime(): Fetch the time from timer server once (e.g. after bootup) and from then on add elapsedRealtime() to that initial value (minus the elapsedRealtime value of when you get the timerserver value).
If you use the GPS location provider, getTime() will return the UTC time derived from the GPS signal, rather than the device time. The GPS location provider can work offline - but it will be much slower to obtain a fix compared to being online when it can access the A-GPS info.
I'm doing a camera application that will automatically geo-tag each picture taken. Using
LocationManager.requestLocationUpdates() //simply to get the GPS running
LocationManager.getLastKnownLocation() //for each picture, to get coordinates
is mostly enough to simply pluck out coordinates from the phone as fast as possible, since it is still a camera application and you don't want to waste time getting GPS data.
(Assume using GPS_PROVIDER only, not NETWORK_PROVIDER pls)
However the issue will be if the user enters a tunnel for example and the phone is unable to continue getting updates. 10 minutes later when getLastKnownLocation() is called, I will get an outdated location.
I want to find a way in which I can set an 'expiry' time on the Location, depending on individual comfort level.
In other words, keep using getLastKnownLocation(), but if the data is (for example) more than 5 minutes old, don't bother with it, and I rather have a 'null' location. if the data is 2 minutes old however, that still is fine
You can implement this yourself. There's nothing in the underlying API that includes this, but it's perfectly fine to stash the time that you initiated the request (or got the last one) in your app, perhaps in a SharedPreferences. You also have to be weary of things like how fast the user is moving, etc.., so in general you might need to put a fair amount of thought effort into determining how you want to do this. There's not any way (in the API) to find out how fresh the call to .getLastLocation() will get you. For a few minutes it's probably best to employ the technique I mentioned. For a lot longer you might want to consider something like an AlarmManager (which you should be using anyway if your app runs on a timescale that is that long). You seem to be using .getLastLocation more than I do, however. I often simply just request updates and then "put the dot down" whenever I get the first update. In general I've found that .getLastKnownLocation() isn't really all that reliable, but maybe that's just because I don't use apps with my location very often.
Managed to find out that each Location returned had a time variable
long time_a = my_loc.getTime();
We can use this to compare with
Calendar cal = Calendar.getInstance();
long time_b = cal.getTimeInMillis();
long interval = time_a - time_b;
The interval is then the 'validity' of the location fix, and can be easily used for my purpose :)
Hello
In my android application i would like to get Time since when the app is opened.
Initially what i tried was getting the time when the app is loaded from the server and then taking the difference with the current time from the device.But by doing that if the user changes the time then i willnot be getting the actual time.
Its not posiible to hit the server again for the same.
Is there any way to achieve this in android?
Please share your valuable suggestions.
Thanks in advance:)
Try the "SystemClock" class, "uptimeMillis()" method.
Store the result in a variable when the app starts.
Echoing what I said for your other question, you first need to become familiar with the activity lifecycle and understand the novel meanings (almost meaninglessness) of common words like "open" and "start" in the life of an android app.
There isn't any way you can prevent the user from changing the system time - you just don't have the right to do that to users. Normally this should be a rare event, unless you do something that makes them want to, such as lock them out of a free version of your app after so many minutes. (However if the phone is on a mobile network, presumably the mobile network occasionally adjusts its time to correct for errors in the device's oscillator, or administrative time changes)
What you can do is check the system time on every entry point to your application. If it ever goes backwards, well... something is going on. If the clock has been set back, you could assume no time between the calls with the negative time difference and resume your time meter from there, at least keeping all the previous used time in your record.
It may be that there are cpu cycle counters which you could query and correlate to system time, but this may be highly device specific and may in fact be resettable. And it may get weird if the cpu frequency is demand throttled.
You might be able to set a countdown timer as a bound on the maximum possible time between entry points at which you could meter. I don't know if these work reliably across system time changes or not - ideally they would. Testing or reading the source will reveal.
Use elapsedRealtime in your onCreate() store it. More reliable.