Android persistent socket connection rules - android

I have been doing some testing for a custom push notification solution for Android devices using persistent sockets. I would like to share my findings and validate the results.
Simple Description
The applications runs a foreground service and establishes a connection with the server and maintains that connection via aggressive pinging (# 10 secs interval). If the connection is ever detected as dead, the app keeps trying to reconnect indefinitely. The server sends notifications via duplex channel.
Test 1 :
Pinging is done using a timer at 10 second intervals.
Server sends notification every minute.
Applications acquires wifi and wake locks.
Duration : 8 hours
Battery loss : ~14%
Test 2 :
Pinging is done using AlarmManager at 10 second intervals.
Server sends notification every minute.
Application acquires only a wifilock
Duration : 8 hours
Battery loss : ~7%
Assumptions: An incoming network packet automatically wakes up the CPU, thus no need for a wake lock. Using AlarmManager to ping(instead of timers) means we do not need a wakelock.
Removing that wakelock really seemed to help the battery. Surprisingly, the aggressive pinging on either solution did not affect the battery life as much as I would have expected. (We had many other tests including one where the application just held a wifilock and did nothing which caused around 4% to 5% battery loss over the same period)
Since the application was able to successfully send all the ping requests and receive all the incoming messages, I believe my assumptions are correct. But I would love to get some confirmation from any experts.
One more question:
If the application was to instead listen for incoming connections. I would need to hold a wakelock in this case, correct? An incoming connection does not wake up the CPU? We are not going down this route, but just wanted to confirm.
Also, please do not recommend GCM, it has been ruled out by company policy.
Thanks.

Since there has been some interest in this question and no confirmations, I will just respond now. It has been a while since the tests were done, and a production level solution has been created and rigorously tested. Removing the wake lock still helped the battery and no other issues were found such as missing ping requests or incoming notifications, so that is the only validation that I received on the said assumptions.
Additional Things to Note:
In the OnReceive method of the BroadcastReceiver for the pinging alarm, if you are not directly calling on the socket (spawning a new thread or intent), you will need to hold a wake lock until the ping request is finished. Android holds a wake lock only until OnReceive returns, after that it is possible(but rare) that the CPU may sleep before the ping is finished.
Use a High Performance Wifi Lock if the notifications are sensitive.
There was one other device specific issue that affected the solution, it is covered here.
Update
Ran into the following issue with Android 5.1 : Android Issue
Update 2
Need to code around Doze mode for Android 6.0 : Doze Mode

Related

Using internet during sleep - Android Service

I am currently developing an android app that gets data from a web server at a user specified interval (5 min, 10 min...). I am using an AlarmManager and a WakeLock. The alarm goes off as expected every 5-10 minutes. The internet connection though doesn't seem to be working during sleep. Most people suggest that I use a WifiLock. Correct me if I am wrong but isn't WifiLock only used to keep WiFi alive? What about 3G-4G mobile data? Does WifiLock keep that connection alive aswell?
Starting with Android 6 due to the new Doze Mode the device enters sleep even with wakelocks, they are ignored.
The way to avoid the device to enter sleep is to start a foreground Service with a non-dismissable notification.
You can't get network access while the device is in Doze mode. If you are hoping to receive notifications or updates from a web service, use Firebase Cloud Messaging, or just defer the network call until the next time it wakes up. You can see more information about Doze restrictions here:
https://developer.android.com/training/monitoring-device-state/doze-standby.html#restrictions
Also, if you are curious about how to check if phone is in Doze mode:
https://developer.android.com/reference/android/os/PowerManager.html#isDeviceIdleMode()

How to send a ping once a minute to Server in a RELIABLE manner?

In my Android application I need to send a message to the server (basically a ping) once a minute when a certain feature is activated. The feature may be activated for 2-3 hours, so it's important that the ping is sent continuously and in a timely fashion.
To achieve this I am currently using AsyncTasks (for sending the request), launched once a minute via a foreground Service, which is scheduled with alarmManagers' setExactAndAllowWhileIdle. The foreground service does have a partial wakelock too!
Unfortunately it looks like Marshmallow's doze mode ends up swallowing the alarms at some random point. This happens EVERY TIME and at arbitrary points. Sometimes the app sends pings for 2 hours without problems, sometimes only for 30 minutes, before they don't go off anymore (and then restarting 10-15 minutes later).
What can I do to get the ping sent continuously? It is incredibly important for the app. The only other alternative I can see is that I use the GCM to send high-priority messages every 5 minutes or so to keep it alive, but I that would be a terrible hack.
Ask the user to add your app to the battery optimization whitelist.
Or, ask the user to only use this feature when connected to a charger or external battery pack.
Or, ask the user to jiggle their device every few minutes for a few moments, to try to convince Android that it is not sitting idle on a nightstand.
Or, build your own custom ROM, where you take steps to modify Android to allow your app to consume arbitrary amounts of power, then have users install your custom ROM.
Note that AFAIK your GCM solution would need to be every minute, not every five minutes, if you want to send "pings" every minute. The GCM solution does not prevent the device from going into Doze mode; it merely allows you to send messages to the app and have a brief window of connectivity. It is possible that the window is 5+ minutes, but I wouldn't count on it.
Note that you are saying, in effect, that the CPU will need to be on continuously for your 2-3 hour window, due to your partial WakeLock. You are also saying that some radio (WiFi or cellular) will be in a high-power mode for much of that time as well, since they go through a series of power states with relatively slow transition times, and an every-minute set of packets will push the radio back into the high-power state. What you are doing is exceptionally bad for battery life.
If your users agree that what you are doing is "incredibly important" to them, they will not mind adding you to the whitelist, or only using this feature while on a charger.

How to make the Android device hold a TCP connection to Internet without wake lock?

I want my application to be connected to server though the mobile connection, yet allowing the device to go into sleep mode. I expect it to wake up when IP packates arrives.
How can this be done? How to receive "interrupts" from the Internet without draining battery?
When you are blocked on a read from a tcp stream the device can go into a deep sleep and when tcp traffic comes in it will briefly wakeup the device, as soon as a bit is read in you start a wakelock until you have received the whole transmission then release it.
Here is an example with web sockets, I've ran this app for over 12 hours in the background with no battery impact.
https://github.com/schwiz/android-websocket-example
The client is here, the blocking read is in the start method.
https://github.com/schwiz/android-websockets/blob/master/src/com/codebutler/android_websockets/HybiParser.java
I've been using long living TCP connections on Android without a wake lock for some years now.
My experience is that when data arrives on a TCP connection and the device is in deep sleep, it will be woken up for a short period of time at least. Waking up the device could take up to ~2 minutes sometimes, but it's usually done within a few seconds.
Now that the device is awake, the receiving process has some time too process the data. Now either the process is able to do so before the device is put back into deep sleep, or the device will be put into deep sleep suspending also the process. The important thing here is that the data is not lost, it remains in the memory and the process is able to resume the work processing the data the next time the device leaves deep sleep. Of course, this means that if the sender awaits an answer to his data, it may take some time, until he gets it.
You could take a wake lock as soon as your network library notifies you that a new message was received. But if you done, then make sure to handle the lock properly, i.e. ensure that it is released at some point and in every code path. I personally never experienced the need for a wake lock, the Android device was always long enough awake to process the request. But your millage may vary.
So this is very old but i ended up testing the behaviour #Flow described and just wanted to confirm that there seam to be arbitrary delays sometimes between the arrival of the data and the wakeup of the device.
I tested using a tcpClient implementation and an mqttimplementation. The idea was to see if there is an requirement of instantly getting the wakelock since this delay appeared in my mqtt implementation.
Test steup:
we have 2 services one running the tcpclient and one running the mqttclient in different apps
Both Services run on the same phone with the same permissions in the background.
The Server sends in both cases an "ping" message.
Our client implementation acquires a wakelock as soon as possible and reads the current Date.
for the tcpclient this is instantly
for the mqttclient the wakelock can only be acquired after the arriving data has been propagated through the networking libraries
we send back an response pong message including the read date
this send happens after wakelock release to see if this further delays the response time
the server logs incoming messages with the arrival and the read date
It appears that in both implementations there sometimes is an arbitrary delay to the call to our code. This makes it most likly that there is a delay to the wakeup of the device and not to the acquire of the wakelock.
this delay can be sometimes seen on all devices(tested on huaweip20light, HMD Global#Nokia 7.2, samsung#SM-N960F)
this delay seams more likly to happen on the HMD device higher api and victim of the stricter battery optimisations android established
Google Cloud Messaging might be what you are looking for:
http://developer.android.com/guide/google/gcm/index.html

Android - slow network acces when phone is in iddle mode

I have application which for every 10 seconds do some request to server (http client). I read a lot about application life cycle. My application has service with foreground flag and it's work well (application work all time) when android is "active". I don't have phone with real android, so I am testing on emulator, but my friend testing it on smartphone and he notice that when he leave his phone, request are post for 10, 30 minutes, even hour. If he turn on screen, then request time is back to 10 seconds (he have access to server so he see logs). Is this known behavior? Because he installed gmail notifier from google, and this same problem (big delay). Any solution for this? My service have timer task (so request is sent in async task)
Regards
First of all, if you're polling every 10 seconds, that's gonna drain a lot of battery and network bandwidth.
I recommend using a lower frequency or server push.
For the polling issue, how do you implemented the polling ?
Do you use timers ? if so, what options do you pass in ? Or do you use a thread that sleeps for 10 seconds ?
Depending on the version, Android may turn off all processes, or delay network requests to run every 30 minutes to preserver battery power and bandwidth. (Starting up the network components drain a lot of battery than keeping them running. So If your app turns ON network, do a poll, then simply turn it off, Android may schedule it to align with all other requests on the system.)
Can you provide us more info about how you do the polling ?
UPDATE
You might have to schedule a 'WakeLock' so android knows when to wake up for your service. I think, by default, android doesn't wake up for timer requests that are scheduled very frequently and it schedules them as I explained. WakeLocks on the other hand can force android to wake up.
See this question and WakeLock Documentation
Make sure you pass the correct parameters, so you don't turn the screen ON. (Would be really annoying.)
UPDATE
I still recommend using server push for this, which will save battery and bandwidth while keeping the updates real time.

Android : Listen to packet data when Android in sleep mode

As stated in the answer to a previous question, the CDMA and GSM radios are kept on, even after the CPU is put to sleep on an Android device.
My questions are...
When a call is received, what is it that wakes the CPU / phone up ?
Is there a similar mechanism to wake my application up when data is received via an active TCP connection to a server, even after the phone has gone to sleep mode ?
Data cannot be received when the CPU is asleep.
The CPU needs to be woken up once in a while to see if there is new data. In your code to check for the new data, if there is new data, you can stay awake and go off and do your processing.
You definitely want to learn about BroadcastReceiver and android alarms. Basically, you can tell Android to send you an Alarm every 5 minutes or whatever, even if it is sleeping. Your BroadcastReceiver wakes up the CPU when it gets the alarm from android, and stays awake long enough to check if you have new data, or whatever you are trying to do. If you have new data, you can then tell the CPU to stay awake and you can go off and process your new data.
Here is a reasonable tutorial. And of course the Android Developer docs are helpful.
You might want to look into sending push notifications to your device (if you don't specifically need TCP).
Check out the (free) Android Cloud to Device Messaging (C2DM) service from Google (http://code.google.com/android/c2dm/).
It takes a little work to get set up, and is only supported on 2.2+, but really simplifies the client/server architecture.

Categories

Resources