Несоответствие SensorEvent.timestamp

мое приложение выполняет подсчет фонового шага с использованием API-интерфейса датчика детектора шага, представленного в android 4.4.X.

Для моего приложения важно знать точное время (по крайней мере, с точностью до секунды) каждое событие шага.

потому что я выполняю пакетное дозирование, время onSensorChanged(SensorEvent event) было вызвано не то же самое время, когда произошло событие шага - я должен использовать поле event.timestamp для получения времени события.

документация об этом поле:

Время в наносекундах, при котором произошло событие

Проблема:

В некоторых устройствах (например, Moto X 2013) кажется, что эта временная метка - это время в nano секундах с момента загрузки, в то время как в некоторых устройствах (например, Nexus 5) она фактически возвращает универсальное системное время в nano секундах так же, как System.currentTimeMills() / 1000.

Я понимаю, там уже есть старая открытая проблема, но поскольку введен пакетный пакет - , важно использовать это поле знать время события, и больше нельзя полагаться на System.currentTimeMills()

Мой вопрос:

Что делать, чтобы всегда получать время события в системных миллисекундах на всех устройствах?

Ответ 1

Вместо сравнения "2 дня" вы можете просто проверить, меньше ли event.timestamp, например. 1262304000000000000 - таким образом у вас будет только проблема, если пользовательские часы установлены в прошлом, или их телефон работает в течение 40 лет...

За исключением того, что комментарий этот вопрос указывает, что иногда это даже миллисекунды вместо наносекунд. И другие комментарии указывают на то, что применяется смещение, и в этом случае он не будет ни системным, ни временным временем.

Если вам действительно нужно быть точным, единственный способ, по которому я могу видеть, - это сначала зафиксировать событие (или два для сравнения) с max_report_latency_ns, установленным на 0 (то есть без пакета), и сравнить временную метку с системное время и/или elapsedRealtime. Затем используйте это сравнение, чтобы вычислить смещение (и, возможно, решить, нужно ли вам компенсировать миллисекунды против наносекунд) и использовать это смещение для ваших пакетных событий.

например. захватите пару событий, желательно на пару секунд, записывая System.currentTimeMillis() каждый раз, а затем делайте что-то вроде этого:

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);

И затем для ваших пакетных событий

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

Одно последнее предупреждение - даже если вы все это сделаете, если системное время изменится во время вашего захвата, оно может повлиять на ваши метки времени. Удачи!

Ответ 2

Я нашел решение для решения проблемы. решение предполагает, что временная метка может быть только одной из двух: системная метка времени или время загрузки:

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;
}

Ответ 3

В соответствии с ссылка в вашем вопросе:

Это, по сути, "работает по назначению". Временные метки не являются определяемый как время Unix; они просто "время", что только действительный для данного датчика. Это означает, что временные метки могут если они исходят от одного и того же датчика.

Итак, поле timestamp может быть полностью не связано с текущим системным временем.

Тем не менее; если при запуске вы должны были взять два образца датчика, без дозирования, вы могли бы рассчитать разницу между System.currentTimeMillis() и меткой времени, а также частное от различий между разными временами, которые вы должны иметь возможность конвертировать между разными временами

//receive event1:
long t1Sys = System.currentTimeMillis();
long t1Evt = event.timestamp;

//receive event2:
long t2Sys = System.currentTimeMillis();
long t2Evt = event.timestamp;

//Unregister sensor


long startoffset = t1Sys - t1Evt; //not exact, but should definitely be less than a second, possibly use an averaged value.
long rateoffset = (t2Sys - t1Sys) / (t2Evt - t1Evt);

Теперь любая временная метка от этого датчика может быть преобразована

long sensorTimeMillis = event.timestamp * rateoffset + startoffset;