Potential issue with Time.unscaledDeltaTime on 2018.2.20f1

Hi all,

I am encountering an issue with the Time.unscaledDeltaTime not being properly set when the application is paused or out of focus. I am running the following script on Android device using builds from 2017.2.0f3 and 2018.2.20f1. This is the scenario I am trying;

  • Launch application

  • Once loaded, I lock the device

  • I start a timer (on another device) to keep track of how long the game has been actually suspended

  • I press the lock button on the device again and the application is resumed

  • Simultaneously I stop the timer

  • The first Update call that gets executed should report that the Time.unscaledDeltaTime since last frame

  • The expected result is that the Time.unscaledDeltaTime is equal to the time that the application has been paused (roughly the same to that reported by the timer)

  • What I actually get is a value less than expected, say if the game has been suspended for 40s the Time.unscaledDeltaTime is set to 16s.

  • This behaviour was noticed in 2018.2.20f1 but not reproducible on 2017.2.0f3 (works correctly here)

Can someone verify or explain why this is happening?

using System;
using System.Text;
using UnityEngine;

public class TimeDemo : MonoBehaviour
{
    private bool logNextDeltaTime;
    private float lastUnscaledTime;
    private StringBuilder logBuilder;

    private void Awake()
    {
        logBuilder = new StringBuilder();
    }

    private void Update()
    {
        if (logNextDeltaTime)
        {
            var diff = Time.unscaledTime - lastUnscaledTime;
            logBuilder.AppendLine(string.Format("Application is updating frame {0} with time {1} (+{2}s). Time difference should be +{3}s", Time.frameCount, Time.unscaledTime, Time.unscaledDeltaTime, diff));
            logNextDeltaTime = false;
        }
    }

    private void OnApplicationFocus(bool focus)
    {
        logBuilder.AppendLine(string.Format("Application is focused - {0} in frame {1} with time {2}", focus, Time.frameCount, Time.unscaledTime));
        if (!focus)
        {
            logBuilder.AppendLine(string.Format("Last unscaled time {0}", Time.unscaledTime));
            lastUnscaledTime = Time.unscaledTime;
            logNextDeltaTime = true;
        }
    }

    private void OnApplicationPause(bool pause)
    {
        logBuilder.AppendLine(string.Format("Application is paused - {0} in frame {1} with time {2}", pause, Time.frameCount, Time.unscaledTime));
        if (pause)
        {
            logBuilder.AppendLine(string.Format("Last unscaled time {0}", Time.unscaledTime));
            lastUnscaledTime = Time.unscaledTime;
            logNextDeltaTime = true;
        }
    }

    private void OnGUI()
    {
        GUI.skin.GetStyle("label").fontSize = 35;
        GUI.skin.GetStyle("button").fontSize = 35;

        if(GUILayout.Button("Clear Log", GUILayout.Width(300), GUILayout.Height(100)))
        {
            logBuilder = new StringBuilder();
        }

        GUILayout.Label(logBuilder.ToString());
    }
}

A weird fact that I noticed is that when the Android device is connected via USB with the machine, the unscaledDeltaTime values are correct. When it is disconnected, it doesn’t work as expected. I updated the code to use the Android elapsedTime from its local clock and the values received are correct as seen in Unity 2017.2.0f3.

Can someone confirm this issue?

using System;
using System.Text;
using UnityEngine;

public class TimeDemo : MonoBehaviour
{
    private bool logNextDeltaTime;
    private float prevTimestamp;
    private StringBuilder logBuilder;

    private void Awake()
    {
        logBuilder = new StringBuilder();
    }

    private void Update()
    {
        if (logNextDeltaTime)
        {
            #if UNITY_ANDROID && !UNITY_EDITOR
            var currTimestamp = UnscaledTime();
            #else
            var currTimestamp = Time.unscaledTime;
            #endif

            var diff = currTimestamp - prevTimestamp;
            logBuilder.AppendLine(string.Format("Application is updating frame {0} with time {1} (+{2}s). Time difference should be +{3}s", Time.frameCount, Time.unscaledTime, Time.unscaledDeltaTime, diff));
            logNextDeltaTime = false;
        }
    }

    private void OnApplicationFocus(bool focus)
    {
        logBuilder.AppendLine(string.Format("Application is focused - {0} in frame {1} with time {2}", focus, Time.frameCount, Time.unscaledTime));
        if (!focus)
        {
            OnSuspended();
        }
    }

    private void OnApplicationPause(bool pause)
    {
        logBuilder.AppendLine(string.Format("Application is paused - {0} in frame {1} with time {2}", pause, Time.frameCount, Time.unscaledTime));
        if (pause)
        {
            OnSuspended();
        }
    }

    private void OnGUI()
    {
        GUI.skin.GetStyle("label").fontSize = 35;
        GUI.skin.GetStyle("button").fontSize = 35;

        if(GUILayout.Button("Clear Log", GUILayout.Width(300), GUILayout.Height(100)))
        {
            logBuilder = new StringBuilder();
        }

        GUILayout.Label(logBuilder.ToString());
    }

    private void OnSuspended()
    {
        #if UNITY_ANDROID && !UNITY_EDITOR
        prevTimestamp = UnscaledTime();
        #else
        prevTimestamp = Time.unscaledTime;
        #endif

        logNextDeltaTime = true;
        logBuilder.AppendLine(string.Format("Last unscaled time {0}", prevTimestamp));
    }

    private float UnscaledTime()
    {
        var systemClock = new AndroidJavaClass("android.os.SystemClock");
        return systemClock.CallStatic<long>("elapsedRealtime") / 1000f;
    }
}

Can you try with 2018.3 ?

Long story short, android system timer sometimes jumps back… don’t remember the details, but there is faulty implementation in Android OS itself.

There were numerous attempts to workaround that, I think one workaround was applied in 2017, but then reverted back, because it created a new issue. (This might be what you’re seeing)

But then there was a more stable workaround done in 2018.3.

Thanks for your reply and explanation. Unfortunately, we cannot update to 2018.3 for the time being. Found a different approach by using android.os.SystemClock as shown in the previous code sample.

Thanks

1 Like