Sending keep-alive Messages on Android even if the device is in sleep/doze mode
-
Hi there,
I have a problem with my QtApp since Android 7. I'm sending every 60 seconds a keep-alive message to a webserver via QNetworkRequest. After that, the app processes the reply from the webservice.
Now I have the problem, that the app does not send any keep alive messages after the phone/tablet gets into standby mode. Unfortunately i cant use push notification for my purpose. So is there any known solution or approach for that? Maybe a service class which runs in bg?
Any ideas?
Greetings,
wowalive -
Finally got it..
I've experimented a lot using services in relation to my problem. Noting really helped, because of the doze mode and app standby introduced in API 23.The following restrictions apply to your apps while in Doze:
- Network access is suspended.
- The system ignores wake locks.
- Standard AlarmManager alarms (including setExact() and setWindow()) are deferred to the next maintenance window.
- If you need to set alarms that fire while in Doze, use setAndAllowWhileIdle() or setExactAndAllowWhileIdle().
- Alarms set with setAlarmClock() continue to fire normally — the system exits Doze shortly before those alarms fire.
- The system does not perform Wi-Fi scans.
- The system does not allow sync adapters to run.
- The system does not allow JobScheduler to run.
In API 24 and 26 further restrictions, like limited implicit broadcasts and limited gps background behavior, are added.
Firstly I tried to use a service with a native timer and asynctask for requesting data from a server, but the network connection will cut off after a couple of minutes and app tasks will be deferred to the maintenance window of doze. This affects the app even if I whitelist the app in battery optimization and enable partial wake locks to keep the cpu awake (see https://developer.android.com/training/monitoring-device-state/doze-standby#support_for_other_use_cases).
With the AlarmManager (using setAndAllowWhileIdle() or setExactAndAllowWhileIdle()) you are able to set alarms that fire methods even if the device is in doze mode , but you cant fire alarms more than once per 9 minutes, per app. So for me this wasn't a solution, because I need to request every minute.
So referring to the background processing overview and the app standby exceptions I decided to implement a foreground service.
This solution was exactly what I was looking for. Now everything works fine. My Qt main thread does all the processing, and a simple foreground service holds the application awake. If you use that, pay attention to the high battery consumption.
-
@Wowalive
This is a normal App lifecycle. If you need your code to run continuously in the background you need to implement an Android service.
But this has been discussed several times already. -
okay thanks for the reply.
I'm just not sure what exactly I need a service for? Only for the NetworkRequest to send the alive-message or for the timer which calls the NetworkRequest? And what about the processing of the server-request? Do I need a service for processing the data too?
-
@Wowalive
you need a service for everything which needs to be run permanently in the background.
If needed your app needs to request data from the service.@Wowalive said in Sending keep-alive Messages on Android even if the device is in sleep/doze mode:
I'm sending every 60 seconds a keep-alive message to a webserver via QNetworkRequest. After that, the app processes the reply from the webservice.
and you mean that such an keep-alive message may contain a notification message from the server in it's response?
-
If the server receives a keep-alive message from the mobile device, it checks if there are any new tasks / operations for the mobile client. If so, the reply (QNetworkReply) will contain these task data, which will be processed by the main thread (for example to create a popup notification).
Due to security reasons I can't use push notification. Thats why I need to pull data regulary, even if phone is in sleep mode.
I have read about foreground services. Do I need this for my purpose?
-
@Wowalive said in Sending keep-alive Messages on Android even if the device is in sleep/doze mode:
I have read about foreground services. Do I need this for my purpose?
see this. Not you need a background service.
Just so you know. Using a background service like you intend to is a battery drainer.
May i ask what security reasons exactly preventing you from using push notifications?
-
Okay thanks. So I need a native background service / method for sending, receiving and processing data? Did I understand it correctly?
@raven-worx said in Sending keep-alive Messages on Android even if the device is in sleep/doze mode:
May i ask what security reasons exactly preventing you from using push notifications?
I'm working with sensitive customer data and one of the requirements is not to use privacy critical servers like googles fcm / gcm. I do not know if there is even a possibility to use push notification without accessing these servers.
Beyond that I have to send the gps position of the mobile device to the webservice as a payload of the alive-message every minute.
-
@Wowalive said in [Sending keep-alive Messages on Android even if the device is in sleep/doze mode]
Beyond that I have to send the gps position of the mobile device to the webservice as a payload of the alive-message every minute.
constant GPS usage, Background data exchange and computation, your phone battery will be empty in a matter of very few hours!
Also I hope this is not intended to be a cross plattform application? Because its almost guaranteed, that the app would be rejected before even getting a background service permission from Apple.
-
@Wowalive said in Sending keep-alive Messages on Android even if the device is in sleep/doze mode:
I'm working with sensitive customer data and one of the requirements is not to use privacy critical servers like googles fcm / gcm. I do not know if there is even a possibility to use push notification without accessing these servers.
Would it be possible to send a push notification "new data is available", which in turn causes your app to request the data on a secure channel?
That would avoid the constant polling from phone side, and as the push notification just contains an info it should not be that critical.
For me it sounds like a balanced compromise. Am I missing something?
-
@Wowalive
using a WebSocket approach would be even better.
The server just sends the data when there is something to send. -
Yes I've thought about this approach too. It's a good compromise for updating the data in a secure and efficient way.
But what about updating the gps position in a given cycle? It's necessary for me, that the server is informed about the position and the connectivity state (online/offline) of the mobile device every minute or so.
Like I already said, battery drain isn't a problem for me though.
-
@Wowalive
the big advantage of a WebSocket is that only the really needed data is transferred.
There is only a single HTTP connection kept open. No HTTP connection negotiation data overhead for each poll request etc.
One possibility could be if the connection is closed you can assume that the device is disconnected.With the linke i've posted in my first post you can implement the service with Qt. For the service <-> app communication you can use any IPC mechanismn (e.g. QtRemoteObjects to connect to a signal emitted from your service)
-
I created a Service, following this tutorial. The example from @BogDan-Vatra does not work for me (Program client has been terminated).
The example from bbernhard (https://github.com/bbernhard/qtandroidservices_example) works for me. The service starts and keeps running, but somehow I cant call any Methods from service class. I suspect that the onCreate or onStartCommand method from the service will never be called.
Isn't there just a service or method which pretends the main qt app from getting into app standby? So the app will keep running, even if the phone is locked?
-
@Wowalive said in Sending keep-alive Messages on Android even if the device is in sleep/doze mode:
Isn't there just a service or method which pretends the main qt app from getting into app standby? So the app will keep running, even if the phone is locked?
@raven-worx said in Sending keep-alive Messages on Android even if the device is in sleep/doze mode:
This is a normal App lifecycle.
This is how the Android OS works. The OS decides when the app is closed to free up resources.
-
Okay thank you. Then I will try to add an service which sends the network request.
Do you know, if I need a service for all the needed functions? Sending the request, receiving it and processing the data? Or will just the network request wake the app up, so my Qt code can proceed the processing?
-
Finally got it..
I've experimented a lot using services in relation to my problem. Noting really helped, because of the doze mode and app standby introduced in API 23.The following restrictions apply to your apps while in Doze:
- Network access is suspended.
- The system ignores wake locks.
- Standard AlarmManager alarms (including setExact() and setWindow()) are deferred to the next maintenance window.
- If you need to set alarms that fire while in Doze, use setAndAllowWhileIdle() or setExactAndAllowWhileIdle().
- Alarms set with setAlarmClock() continue to fire normally — the system exits Doze shortly before those alarms fire.
- The system does not perform Wi-Fi scans.
- The system does not allow sync adapters to run.
- The system does not allow JobScheduler to run.
In API 24 and 26 further restrictions, like limited implicit broadcasts and limited gps background behavior, are added.
Firstly I tried to use a service with a native timer and asynctask for requesting data from a server, but the network connection will cut off after a couple of minutes and app tasks will be deferred to the maintenance window of doze. This affects the app even if I whitelist the app in battery optimization and enable partial wake locks to keep the cpu awake (see https://developer.android.com/training/monitoring-device-state/doze-standby#support_for_other_use_cases).
With the AlarmManager (using setAndAllowWhileIdle() or setExactAndAllowWhileIdle()) you are able to set alarms that fire methods even if the device is in doze mode , but you cant fire alarms more than once per 9 minutes, per app. So for me this wasn't a solution, because I need to request every minute.
So referring to the background processing overview and the app standby exceptions I decided to implement a foreground service.
This solution was exactly what I was looking for. Now everything works fine. My Qt main thread does all the processing, and a simple foreground service holds the application awake. If you use that, pay attention to the high battery consumption.
-
@Wowalive and others: Thank you for providing this informative thread and sorry for necro bumping.
I have a similar task ahead and am trying your approach. So far I managed to create a foreground service, but my activity still gets suspended as soon as the device display is off. At least the permanent TCP connection to the server cuts off.
@Wowalive: How did you manage to keep your activity awake?