Search code examples
androidc++android-ndkthread-sleepcondition-variable

Android: C++ thread not waking up if screen-locked or in background. Works fine when app is in use


In our Android app, we have UI component and core C++11 module. A thread is running based on std::chrono::system_clock::time_point, such as below:

while(this->m_ConditionVariable.wait_until(lock, this->m_Object.to_time_point())
      == std::cv_status::no_timeout)
{
  // ... handle any notify() or arbitrary sleep breaks
}

Execute();  // <--- not being called consistently 

Now, we are testing with 1 minute time_point. If the app is in use, then the Execute() is invoked as expected. However, if the app is moved to background or if even the screen is locked, then the Execute()-s behavior is not consistent.
Sometimes, it may work properly every minute for 15 mins and after that it will be invoked after 2 minutes or 3 minutes or 10 minutes, instead of fixed 1 minute. Using debugs, we checked that, the time_point supplied is proper.

Suppose if we run the app in debug mode (using Android Studio) then it works fine even in background and screen locked mode.

Does Android have any threading priority for the app running in background?


Update 1: Basically the background thread is collecting location information. I came across below question, which suggests that in Android, when the phone is locked, the thread execution is halted. Am I stuck to that problem?
App seems to stop working when the screen goes to sleep

Update 2: With partial Wake lock, it works fine. But not sure if that's a good solution. If that's the only way, then I would appreciate strategy for how to use it optimally.

Update 3: If I replace wait() with smaller sleep(), then it works fine even without any Android wake lock. However we are yet to do regressive testing on it.


Solution

  • When the device is idle, the CPU is stopped and any thread running is paused (C++ or Java). If it wakes up for any reason your C++ thread will start working again, hence the random behavior: Other apps or services might wake-up the device every now and then.

    Adding a partial wake lock works in your case but that will prevent the CPU from going idle, which will cause some battery drain. If you don't care you can use this approach, if battery live is an issue, you can use the Java alarm API to wake up the device on a regular basis. Then the java API can call the C++ code through JNI.

    Android documentation for repeated alarms: https://developer.android.com/training/scheduling/alarms.html

    For the update 3, using a small sleep rather than wait(), I suspect android is not going in idle mode while a thread is running, maybe it waits for a small timeout without any thread active before it goes idle. This approach will have the same effect on the battery drain than the wake lock.