Подтвердить что ты не робот

System.currentTimeMillis() возвращает неверную метку времени на Huawei

Проблема заключается в том, что System.currentTimeMillis() возвращает неверные миллисекунды с разными диапазонами времени, главным образом в будущем, иногда до 6 месяцев, но варьируется от нескольких секунд до нескольких месяцев.

Устройство, в котором это происходит, - это модель планшета Huawei M2-A201W на android 5.1.1, версия ядра: **3.10.74-gdbd9055**

Мое первое предположение заключалось в том, что NTP каким-то образом испортился со временем, но у меня есть тысячи этих планшетов, а некоторые из них не имеют сетевого подключения, нет SIM-карты, поэтому нет GSM/3G/4G.

Im использует System.currentTimeMillis() для сохранения в столбце таблицы, где была строка, созданная в локальной базе данных sqlite.

Это аномально происходит очень часто (30% каждого вызова System.currentTimeMillis()) на планшетах, которые я использую.

4b9b3361

Ответ 1

Как обходной путь для использования System.currentTimeMillis(), возможно, вы можете позволить обработчику sqlite создавать временную метку и посмотреть, разрешает ли это вашу проблему?

Определите/измените свой "созданный" -колонник с помощью timestamp default current_timestamp или с помощью default(strftime('%Y-%m-%d %H:%M:%f', 'now')), если вам нужны миллисекунды, например:

sqlite> create table my_table(id integer primary key autoincrement not null, name text, created timestamp default(strftime('%Y-%m-%d %H:%M:%f', 'now')) not null);

sqlite> insert into my_table(name) values ('MyTestRow1');
sqlite> insert into my_table(name) values ('MyTestRow2');

sqlite> select * from my_table;

1|MyTestRow1|2017-08-07 10:08:50.898
2|MyTestRow2|2017-08-07 10:08:54.701

Ответ 2

API-интерфейс java API System.currentTimeMillis() на платформе Android использует POSIX api gettimeofday, чтобы получить время в миллисекундах. См. здесь.

static jlong System_currentTimeMillis(JNIEnv*, jclass) {
    timeval now;
    gettimeofday(&now, NULL);
    jlong when = now.tv_sec * 1000LL + now.tv_usec / 1000;
    return when;
}

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

Лучше проверить возвращаемое значение каждого вызова API и определить, что делать дальше, если произойдет ошибка.

Поэтому я предлагаю более надежный метод в JNI с вашей собственной реализацией, как показано ниже. Вызовите эти API POSIX по порядку, если gettimeofday не удалось, вызовите clock_gettime, если он не сработал снова, вызовите time.

struct timeval now;
if (gettimeofday(&now, NULL) != 0) {
    struct timespec ts;
    if (clock_gettime(CLOCK_REALTIME, &ts) == 0) {
        now.tv_sec = ts.tv_sec;
        now.tv_usec = ts.tv_nsec / 1000LL;
    } else {
        now.tv_sec = time(NULL);
        now.tv_usec = 0;
    }
}
jlong when = now.tv_sec * 1000LL + now.tv_usec / 1000LL;
__android_log_print(ANDROID_LOG_INFO, "TAG", "%lld", when);

Ответ 3

Как получить выборку временной метки, выполнив команду "date +% s" в ядре Linux?

Здесь "+% s" находится в секундах с 1970-01-01 00:00:00 по UTC. (Руководство GNU Coreutils 8.24)

  try {
            // Run the command
            Process process = Runtime.getRuntime().exec("date +%s");
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));

            // Grab the results
            StringBuilder log = new StringBuilder();
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                log.append(line);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

Если вы напечатаете это,

Log.e("unix_time: ", "" + log.toString());

Вы получите временную метку Unix, например. 1502187111

Чтобы преобразовать его обратно в объект даты, умножьте его на 1000, так как java ожидает миллисекунды,

Date time = new Date(Long.parseLong(log.toString()) * 1000);
Log.e("date_time: ", "" + time.toString());

Это даст вам простой формат даты. например Вт Авг 08 16:15:58 GMT + 06: 00 2017

Ответ 4

Если у вас нет SIM-карты, поэтому нет GSM/3G/4G, ваш телефон не сможет обновить правильное время на основе предоставленного в сети времени/зоны.

введите описание изображения здесь

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

Проверьте, заблокирован ли NTP (UDP-порт 123) приложениями с помощью Socket или DatagramSocket. Примечание. NTP применяется к сценарию, в котором часы всех хостов или маршрутизаторов в сети должны быть одинаковыми. Если ваше устройство переключается на две (или более) разные сети и получает время, обновляемое из разных источников, оно может меняться во времени.

В конечном счете, ваше системное время меняется, поэтому он колеблется. Если вы вручную System.currentTimeMilis() после ручного отключения автоматической даты и времени, я считаю, что он не колеблется (нет аномалий). Если это так, то ваш планшет Huewai не содержит ошибок.

Ответ 5

Поскольку вы упомянули, что большинство звонков получают правильное время, и это происходит только в 30% случаев, я бы создал приемник для трансляции ACTION_TIME_CHANGED и ACTION_TIMEZONE_CHANGED, чтобы узнать, когда изменится время. Возможно, это даст вам понять, что меняет время.

Вместе с ConnectivityManager вы можете определить, подключено ли устройство и какой тип соединения у вас есть, возможно, какое-то соединение вызывает изменение времени.

// init the register and register the intents, in onStart, using:
receiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
      getNetworkInfo();
      if (Intent.ACTION_TIME_CHANGED.equals(intent.getAction()))
         Log.d(this.getClass().getName(), "Detected a time change. isWifiConn: " +
             isWifiConn + " isMobileConn: " + isMobileConn);
      if (Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction()))
         Log.d(this.getClass().getName(), "Detected a timezone change. isWifiConn: " +
             isWifiConn + " isMobileConn: " + isMobileConn);
    }
};
IntentFilter filters = new IntentFilter();
filters.addAction(Intent.ACTION_TIME_CHANGED);
filters.addAction(Intent.ACTION_TIMEZONE_CHANGED);
registerReceiver(receiver, filters);
Log.d(DEBUG_TAG, "Receiver registered");
// do not forget to unregister the receiver, eg. onStop, using:
unregisterReceiver(receiver);
//...
private void getNetworkInfo() {
    ConnectivityManager connMgr = (ConnectivityManager)
            getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
    isWifiConn = networkInfo.isConnected();
    networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
    isMobileConn = networkInfo.isConnected();
    Log.d(DEBUG_TAG, "Wifi connected: " + isWifiConn);
    Log.d(DEBUG_TAG, "Mobile connected: " + isMobileConn);
}

Ответ 6

Есть ли у этого устройства реальный аппаратный RTC? Я не мог найти окончательного ответа от поисковых систем и чтения спецификаций. Прогон:

$ dmesg -s 65535 | grep -i rtc

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

[    3.816058] rtc_cmos 00:02: RTC can wake from S4
[    3.816429] rtc_cmos 00:02: rtc core: registered rtc_cmos as rtc0
[    3.816510] rtc_cmos 00:02: alarms up to one month, y3k, 242 bytes nvram, hpet irqs

Если сообщение grep (и вы не указали на весь буфер сообщений ядра) не было, тогда вы получите ответ. У вас нет часов, чтобы держать время на этих устройствах. Вы всегда будете нуждаться в NTP и рабочем сетевом соединении с Интернетом, чтобы поддерживать такое устройство без синхронизации часов с мировым временем.

RTC: https://en.wikipedia.org/wiki/Real-time_clock