From 62d82ffc15b21fcc432fd9e0499c4585cd8d89c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Toma=C5=BEi=C4=8D?= Date: Mon, 14 Jul 2025 13:43:01 +0200 Subject: [PATCH] fix: don't use `CLOCK_MONOTONIC_RAW` on Android Older Android phones have a kernel bug where time is not properly calculated when calling `clock_gettime(CLOCK_MONOTONIC_RAW, ...)`. The returned time either has nanoseconds out of range (outside of [0, 999999999]) or the returned time is not monotonic in regards to previous call or both. The issue is reproducible in Android Studio on arm64 emulators from at least Android 7.0 (didn't try older versions) up to including Android 8.1 (kernel 3.18.94). The issue is in the kernel, these are just the versions of Android emulator with buggy kernels. The kernel commit that fixed this is [1]. Because this fix was backported to various LTS releases of kernels it's hard to find out exactly which kernels are buggy and which not. Therefore always use `CLOCK_MONOTONIC` on Android. The `CLOCK_MONOTONIC` is slowly adjusted in case of NTP changes but not for more than 0.5ms per second [2]. So it should be good enough for measuring elapsed time. --- An option would be to dynamically select `CLOCK_MONOTONIC_RAW`/`CLOCK_MONOTONIC` at runtime by checking at init time that `clock_gettime(CLOCK_MONOTONIC_RAW, ...)` returns nanoseconds in range. Testing showed that nanosecons are out of range for 999/1000 cases. I guess this could be good enough for support on older phones. But because this would introduce a small perf hit by always reading a global variable for first argument to `clock_gettime` and because `CLOCK_MONOTONIC` does not have that high time deviation, this commit uses `CLOCK_MONOTONIC` on Android always. It is also less burden to maintain. --- [1] https://github.com/torvalds/linux/commit/dbb236c1ceb697a559e0694ac4c9e7b9131d0b16 [2] https://github.com/torvalds/linux/blob/master/include/linux/timex.h#L136 --- src/timer/unix/SDL_systimer.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/timer/unix/SDL_systimer.c b/src/timer/unix/SDL_systimer.c index 0f96319af7..51bd0cf6c5 100644 --- a/src/timer/unix/SDL_systimer.c +++ b/src/timer/unix/SDL_systimer.c @@ -53,7 +53,9 @@ // Use CLOCK_MONOTONIC_RAW, if available, which is not subject to adjustment by NTP #ifdef HAVE_CLOCK_GETTIME -#ifdef CLOCK_MONOTONIC_RAW +// Older Android phones have a buggy CLOCK_MONOTONIC_RAW, use CLOCK_MONOTONIC +// See fix: https://github.com/torvalds/linux/commit/dbb236c1ceb697a559e0694ac4c9e7b9131d0b16 +#if defined(CLOCK_MONOTONIC_RAW) && !defined(__ANDROID__) #define SDL_MONOTONIC_CLOCK CLOCK_MONOTONIC_RAW #else #define SDL_MONOTONIC_CLOCK CLOCK_MONOTONIC