Bug 16831 - Timers not always firing on Android
Summary: Timers not always firing on Android
Status: RESOLVED NOT_ON_ROADMAP
Alias: None
Product: Android
Classification: Xamarin
Component: Mono runtime / AOT Compiler ()
Version: 4.10.0.x
Hardware: PC Mac OS
: Normal normal
Target Milestone: ---
Assignee: Marek Habersack
URL:
Depends on:
Blocks:
 
Reported: 2013-12-16 19:29 UTC by Jon Goldberger [MSFT]
Modified: 2014-12-10 10:14 UTC (History)
2 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
Test project (12.60 KB, application/zip)
2013-12-16 19:29 UTC, Jon Goldberger [MSFT]
Details
Code snippet from desk case (2.31 KB, text/plain)
2013-12-16 19:30 UTC, Jon Goldberger [MSFT]
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED NOT_ON_ROADMAP

Comment 1 Jon Goldberger [MSFT] 2013-12-16 19:30:22 UTC
We're seeing problems with Timers that affect a handful of Android devices.
We have a simple timer that loops at an interval of 200ms and should print
to the console.

On a particular device (Moto X, Android 4.4), the timer sometimes fails to
fire at all. I can best reproduce this when our app is freshly booted, in
which case it repros every time. Otherwise it takes me 10-20 runs or more
to reproduce.

I have tried using both System.Timers.Timer and System.Threading.Timer and
both show the same bug.

We have not gotten a repro on other devices-- the Nexus 5 (Android 4.4) and
Asus K00G (Android 4.2.2).

Our device is very active during a fresh boot, setting up various services.
I suspect it is either related to garbage collection or a thread pool
issue. However I maintain a strong reference to the timer in my Activity to
try and avoid GC-related problems.

Attached are the various snippets for the timer. In the error case, we see
this log, no matter how much time passes (eg, no "TICK / TOCK").

STARTED RECORDING ON
STARTED STOPWATCH
STARTED TIMER
CLEARING TIMER
Comment 2 Jon Goldberger [MSFT] 2013-12-16 19:30:53 UTC
Created attachment 5676 [details]
Code snippet from desk case
Comment 3 Marek Habersack 2014-12-10 10:14:00 UTC
System.Timers.Timer is implemented using System.Threading.Timer, so it is effectively the same code with just one more level of indirection if using the former. The latter is running a loop in a threadpool thread and iterates over the list of registered callbacks/timers waiting between runs for the smallest amount of time to schedule the next due timer. It is, therefore, NOT a reliable source of timed events as every thread can be blocked for any amount of time, especially on devices where there's just a single CPU core or the cores are disabled by default and especially during heavy CPU activity. In order to be able to see what's going on we'd have to be able to reproduce this issue reliably, check the number of threads running, their state (both managed and unmanaged). 
Both timer classes are very simple and for very basic uses. If you require a more reliable timer source I'd recommend using the operating system's setitimer/getitimer APIs directly as they are designed for reliable delivery of timeout events to the application. Each process on Unix systems has 3 different timers available through those APIs:

  * real time
    This one will deliver the SIGALRM signal when it expires and it decrements in real time.
  * virtual
    This one will deliver the SIGVTALRM signal when it expires and it decrements only when the process is actually executing (that is outside system calls).
  * profiler
    The least useful for you, this one delivers SGPROF and is decrementing both in kernel and user space.

You can also implement your own simple timer in the fashion similar to System.Threading.Timer but using a dedicated thread instead of a threadpool one. Note however that it will still be dependent on the number of CPU cores in the device and will NOT guarantee execution in a timely manner.