System.currentTimeMillis() returns incorrect timestamp on Huawei
Asked Answered
B

6

33

The issue is that System.currentTimeMillis() returns the wrong milliseconds with different ranges of time mainly within the future sometimes up to 6 months, but it varies from a few seconds to months.

The device that this is occurring on is a Tablet model Huawei M2-A201W on android 5.1.1 the kernel version is: **3.10.74-gdbd9055**

My first assumption was that the NTP was somehow messing up with the time but I have thousands of those tablets and some of them have no network connection, no SIM card so no GSM/3G/4G.

Im using the System.currentTimeMillis() to save in a column for a table for when was a row created in the local sqlite database.

This anomally happens very often(30% of each System.currentTimeMillis() call) on the tablets that I use.

Brune answered 4/8, 2017 at 14:15 Comment(9)
Does it return the wrong time every time, or just about 30% of calls? If it mostly works, you can call it like 10 times in a row, and then guess from the returned values which is the correct one (majority of them should be like it). (but the answers look more interesting, this is a secondary option).Sill
not every time but 30% of the time, if I use the sqlite database to generate the timestamp how do we know that it actually is working so what native method does Sqlite actually use?Brune
As you are hitting some kind of bug, the best way to answer it is to try it. Do some app (if you can't easily test with the current one modified), which will randomly insert some data into database (probably interleave it with some for delaying loops doing some calculation, to be not in sync with anything timer-based (like delay(msec)), then check the data, if the stored timestamp grows evenly and are connected to the current time, or there are some jumps in the data. If it's truly 30%, then you should see it in few thousand of records easily.Sill
I will try your solution. Also since the devices are offline Im trying to get the GPS time.Brune
Stack Overflow is for programming questions. What is your question?Marhtamari
You mean, sometime the same device shows correct time, sometimes it shows wrong time?Declivity
@Marhtamari the question is why can it be that randomly the System. currentTimeMillis() method returns weird/incorrect timestamps on the same android device and sometimes correct ones? I explained the details of the androi device and how its usedBrune
check Sammy T's answer: #41882560Baer
If your app does network calls, you can use server time. Because system time is not a trusted value (user can change it when he wants), in all of my apps where I need steady time values I use this 'trick' in adding network response headers interceptor which store a delta value between phone and server times.Rhubarb
B
7

As a workaround for using System.currentTimeMillis(), maybe you can let sqlite handle the timestamp creation and see if that solves your problem?

Define/Alter your "created"-column with timestamp default current_timestamp or with default(strftime('%Y-%m-%d %H:%M:%f', 'now')) if you need milliseconds as well, like this:

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

Burletta answered 7/8, 2017 at 10:22 Comment(2)
how does the sqlite generate the timestamp? does it also somehow use the same native call which System.currentMillisBrune
Looks like they have their own implementation in c for this, sqlite.org/src/doc/trunk/src/date.c Not sure it will solve your problem though, you will have to try it out and test on the devices showing weird results.Burletta
D
7

When you don't have SIM card so no GSM/3G/4G, your phone can't update correct time based on the network provided time/zone.

enter image description here

So, devices with the network show the correct time, while other devices without the network can show incorrect time -- you have to manually set the correct time. System.currentTimeMilis() reads the time from your system. g But on power turn, the clock works.

Check if NTP (UDP port 123) is blocked by apps using Socket or DatagramSocket. Note: NTP applies to the scenario where clocks of all hosts or routers on the network must be the same. If your device switch to two (or more) different network and gets time updated from different sources, it can fluctuate time.

Ultimately, your system time is being changed, that's why it is fluctuating. If you manually System.currentTimeMilis() after you manually disable automatic date and time, I believe, it doesn't fluctuate (no anomaly). If this is the case then your Huewai tablet doesn't have bugs.

Declivity answered 10/8, 2017 at 6:25 Comment(0)
F
6

The java API call System.currentTimeMillis() in Android platform use the POSIX api gettimeofday to get the time in milli seconds. See here.

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

It assume every call to gettimeofday will be successful. I guess your problem might happen here.

It's better to check the return value of every API call and determine what to do next if error happen.

So I suggest a more reliable method in JNI with your own implementation like below. Call these POSIX APIs in order, if gettimeofday failed, call clock_gettime, if it failed again, call 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);
Fistula answered 9/8, 2017 at 4:51 Comment(1)
Can you explain how do the other API calls clock_gettime() and time() differ from clock_gettime() method ?Brune
R
4

What about fetching the timestamp natively by running "date +%s" command in Linux kernel?

Here, "+%s" is seconds since 1970-01-01 00:00:00 UTC. (GNU Coreutils 8.24 Date manual)

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

If you print this,

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

You'll get an Unix timestamp e.g. 1502187111

To convert it back to a date object, multiply by 1000, since java is expecting milliseconds,

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

This will give you a plain date format. e.g. Tue Aug 08 16:15:58 GMT+06:00 2017

Recliner answered 8/8, 2017 at 10:23 Comment(3)
why do you think that getting the timestamp natively differ from System.currentMillis ?Brune
I'm suspecting the issue is related to firmware rather than hardware. Most probably because all Huawei phone goes through tons of software customizations e.g. Emotion UI. Again, I'm not completely sure, But I highly recommend you to test with a result from kernel too. @ArlindRecliner
Also, make sure all devices are synced with the same time from phone's settings. @ArlindRecliner
P
4

Since you mentioned that most of the calls are getting the proper time and it only happens 30% of the cases, I would create an receiver for ACTION_TIME_CHANGED and ACTION_TIMEZONE_CHANGED intent broadcasts to find out when the time changes. Maybe this will give you a clue on what is changing the time.

Together with the ConnectivityManager you can detect if the device is connected and what type of a connection you have, maybe some connection is triggering the time change.

// 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);
}
Pressurecook answered 11/8, 2017 at 6:48 Comment(0)
W
1

Does this device have a real hardware RTC? I couldn't find a definitive answer from googling and reading spec sheets. A run of:

$ dmesg -s 65535 | grep -i rtc

from a shell should give you an answer. You should see something like this (will vary with chipset and kernel version):

[    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

If there is no message returned by grep (and you grepped against the whole kernel message buffer), then there's your answer. You have no clock to keep time on these devices. You will always need NTP and a working network connection to the Internet to keep such a device without a clock chip in sync with world time.

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

Wendell answered 13/8, 2017 at 4:25 Comment(6)
<6>[3005741.222717s][2017:08:14 09:31:48][pid:3293,cpu0,system_server]rtc-pl031 fff04000.rtc: pl031_suspend+. <6>[3005741.222747s][2017:08:14 09:31:48][pid:3293,cpu0,system_server]rtc-pl031 fff04000.rtc: pl031_suspend-. <4>[3005750.005432s][2017:08:14 09:31:48][pid:3293,cpu0,system_server]wake up irq num: 86, irq name: RTC0<6>[3005750.005493s][2017:08:14 09:31:48][pid:3293,cpu0,system_server]report_handle: id = 7 length = 5 buff = RTC0Brune
Thats a part of the outputBrune
@Arlind we will need the earliest boot message that has "rtc". And this must be from a cold boot, not a resume-from-suspend.Wendell
I dont know what you mean exactly how can I get that info ?Brune
When you reboot this host, and quickly run "dmesg" after boot, you should see a bunch of kernel messages related with the kernel loading and starting up. Do you see them? Some examples of typical dmesg output: tldp.org/LDP/LG/issue59/nazario.htmlWendell
<6>[ 8.965423s][pid:1,cpu1,swapper/0]rtc-pl031 fff04000.rtc: rtc: year 118 mon 6 day 28 hour 11 min 22 sec 3 time 0x5b5c51db <6>[ 8.966064s][pid:1,cpu1,swapper/0]rtc-pl031 fff04000.rtc: rtc core: registered pl031 as rtc0 <6>[ 10.697235s][pid:1,cpu4,swapper/0]rtc-pl031 fff04000.rtc: setting system clock to 2018-07-28 11:22:05 UTC (1532776925) <11>[ 12.575531s][pid:1,cpu2,init]init: cannot find '/system/bin/audiouartctl', disabling 'audiouartctl'Brune

© 2022 - 2024 — McMap. All rights reserved.