1

Our app can connect to a HVAC device, and need to sample its state every 10 seconds.

The HVAC device expose a Modbus interface and CANNOT buffer samples. We ACTUALLY need to wake up the service every 10 seconds. A typical sample session last from 1 hour to a few hours. (There are various connection types/cables/bridges: OTG + RS232 USB converter, TCP trough a RS232/TCP bridge, Bluetooth classic and BLE through RS232/BT or BLE bridges.)

Of course the user should be able to turn off the display to save battery, and to navigate to other apps, while the sampling session is taking place.

Until Nougat 7.0 our working solution was:

  • Start an IntenService, then set it to Foreground Service
  • Bound to that service, so it's also a Bounded Service (to stop it, propagate interaction with the HVAC device from the GUI, etc.)
  • Acquire a PowerManager.PARTIAL_WAKE_LOCK
  • Use a Thread.Sleep() for the 10 seconds cycle, but also to manage timeouts in the transport implementation of the various connections

Should I post the code? The relevant parts are most common boilerplate.

Despite having no documented guarantees, Thread.Sleep() with a PowerManager.PARTIAL_WAKE_LOCK in a Foreground Service was working perfectly until Nougat 7.0

On our testing Oreo device, both compiling targeting API 26 and 23 (as our previous released version), while not interacting with the app activities (turned off display, other apps in foreground etc.), the service does not wake up, it sleeps until the first interaction with the app.

To be able to start a foreground service on Oreo targeting API 26, I implemented Bikram Pandit's solution from Android O - Old start foreground service still working?. Nothing changed.

I asked for a Battery Optimizations exception, with ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS (as descripted in https://developer.android.com/training/monitoring-device-state/doze-standby#whitelisting-cases ), and granted it. Nothing changed. (And the app was working without it until Nougat 7.0)

The documentation about Oreo's Background Execution Limits, https://developer.android.com/about/versions/oreo/background, states that Bounded Services or Foreground Services should NOT be subjected to these limits. And yet the service doens't wake up.

AlarmManager cannot be used, since from Oreo it can fire at most every 9 minutes, even with setAndAllowWhileIdle() nor setExactAndAllowWhileIdle(). (Again in https://developer.android.com/training/monitoring-device-state/doze-standby#whitelisting-cases)

I also tried using a wait(sleepTime) instead of the Thread.sleep(): it's even worse, it doesn't even wake up when restarting interacting.

I stopped short before re-implementing as a JobIntentService or using JobScheduler/JobService, to reframe every sample as a job, but:

  • IMPORTANT: I would still need the Thread.Sleep() in some of the transport level connection implementations, will that wake up during a job?
  • Would JobScheduler actually allow to run jobs every 10 seconds, or would it bundle them together on Oreo? We actually need a sample every 10 seconds. We probably could relax to 1 minute, but not any larger.
  • Can I retain very complex state (my ModbusDevice object) in JobService, to share it among all those jobs or there would be limitations?

Again, should I post some code? It's most common boilerplate.

GozzoMan
  • 782
  • 9
  • 23
  • Do you mean that your 10 second Thread.sleep in some circumstances doesn't return (evidenced by for example a logcat print on the next line) until the user opens the app to the foreground, at which time the logcat print happens immediately? – Emil Jun 11 '18 at 17:38
  • @Emil yes, exactly. – GozzoMan Jun 12 '18 at 08:00
  • Which phone/tablet do you test on? – Emil Jun 12 '18 at 08:56
  • @Emil A Huawey P20 Lite with Oreo 8.0, it does not work. It does work on a Samsung S6 with Nougat 7.0, a Moto E 2nd with Marshmallow 6.0, a Landvo with KitKat 4.4. – GozzoMan Jun 12 '18 at 09:00

0 Answers0