Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SensorEvent.timestamp inconsistency

my application performs in background step counting using the step detector sensor API's introduced in android 4.4.X.

It's essential to my app to know the exact time (at least accuracy of a second) each step event has accrued.

because I perform sensor batching , the time onSensorChanged(SensorEvent event) been called is not the same time when the step event took place - I must use the event.timestampfield to get the event time.

the documentation about this field is:

The time in nanosecond at which the event happened

The problem:

In some devices (such Moto X 2013) seems like this timestamp is time in nano seconds since boot, while in some devices (such Nexus 5) it's actually returns universal system time in nano seconds same as System.currentTimeMills() / 1000.

I understand, there's already an old open issue about that, but since sensor batching is introduced - it becomes important to use this field to know the event time, and it's not possible to rely anymore on the System.currentTimeMills()

My question:

What should I do to get always the event time in system milliseconds across all devices?

like image 925
Tal Kanel Avatar asked Nov 04 '14 07:11

Tal Kanel


2 Answers

Instead of your "2-day" comparison, you could just check if event.timestamp is less than e.g. 1262304000000000000 - that way you'd only have a problem if the user's clock is set in the past, or their phone has been running for 40 years...

Except that a comment on this issue indicates that sometimes it's even milliseconds instead of nanoseconds. And other comments indicate that there's an offset applied, in which case it won't be either system time or uptime-based.

If you really have to be accurate, the only way I can see is to initially capture an event (or two, for comparison) with max_report_latency_ns set to 0 (i.e. non-batched) and compare the timestamp to the system time and/or elapsedRealtime. Then use that comparison to calculate an offset (and potentially decide whether you need to compensate for milliseconds vs nanoseconds) and use that offset for your batched events.

E.g. grab a couple of events, preferably a couple of seconds apart, recording the System.currentTimeMillis() each time and then do something like this:

long timestampDelta = event2.timestamp - event1.timestamp;
long sysTimeDelta = sysTimeMillis2 - sysTimeMillis1;
long divisor; // to get from timestamp to milliseconds
long offset; // to get from event milliseconds to system milliseconds

if (timestampDelta/sysTimeDelta > 1000) { // in reality ~1 vs ~1,000,000
    // timestamps are in nanoseconds
    divisor = 1000000;
} else {
    // timestamps are in milliseconds
    divisor = 1;
}

offset = sysTimeMillis1 - (event1.timestamp / divisor);

And then for your batched events

long eventTimeMillis = (event.timestamp / divisor) + offset;

One final caveat - even if you do all that, if the system time changes during your capture, it may affect your timestamps. Good luck!

like image 124
CupawnTae Avatar answered Oct 19 '22 00:10

CupawnTae


I found a work-around solution that solving the problem. the solution assumes that the timestamp can be only one of the two: system timestamp, or boot time:

protected long getEventTimestampInMills(SensorEvent event) {
    long timestamp = event.timestamp / 1000 / 1000;

    /**
     * work around the problem that in some devices event.timestamp is
     * actually returns nano seconds since last boot.
     */
    if (System.currentTimeMillis() - timestamp > Consts.ONE_DAY * 2) {
        /**
         * if we getting from the original event timestamp a value that does
         * not make sense(it is very very not unlikely that will be batched
         * events of two days..) then assume that the event time is actually
         * nano seconds since boot
         */
        timestamp = System.currentTimeMillis()
                + (event.timestamp - System.nanoTime()) / 1000000L;
    }

    return timestamp;
}
like image 4
Tal Kanel Avatar answered Oct 18 '22 22:10

Tal Kanel