I work with GCM in my application, and I have a problem.
Most of the time I get the messages right away, but sometimes the messages come after 5 minutes, one after another, like they got stuck on the way. Is this normal?
The GCM framework part on the client phone use a TCP connection on the port 5228. This connection its used for push notifications, but as every tcp connection it can go on timeout with some routers/carriers that apply strict policies to kill inactive tcp connections (tcp idle timeout).
Most wifi routers kills inactive connections after 5 minutes for example, like mine.
The GCM framework use a keep-alive mechanism to send an heartbeat network packet every 15 minutes on wifi and every 28 minutes on 3G. This keep-alive is not always reliable for all users.
I opened the issue to google here:
https://productforums.google.com/forum/#!category-topic/nexus/connecting-to-networks-and-devices/fslYqYrULto
They agree there is currently an issue.
I've yet to notice that in my extremely limited testing so far, but from my understanding of the documentation, that doesn't sound terribly surprising:
GCM will usually deliver messages immediately after they are sent. However, this might not always be possible. For example, the device could be turned off, offline, or otherwise unavailable. In other cases, the sender itself might request that messages not be delivered until the device becomes active by using the delay_while_idle flag. Finally, GCM might intentionally delay messages to prevent an application from consuming excessive resources and negatively impacting battery life.
Between this and language throughout the rest of the documentation, what you've described sounds like exactly what I'd expect. There's no guarantee of immediate delivery; you'll usually have messages delivered right away, but sometimes you won't.
I am finding the same thing as the original poster. It seems to take up to 5 minutes to "wake up" and then it deals with the messages very quickly.
My app is handling text items in a conversation with a deaf person. The caller initiates the conversation, and the deaf person responds by phone. The delay occurs only in the first step, the new message "out of the blue". Once it's done the first one for that (application, device, system-Id?) the others come through very quickly, almost instantaneously.
Related
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.
I'm using WebSockets to allow for real time chat within my android application. When the app is not active and the user recieves a message, GCM works to turn the websockets service on in the background and reenable real time chatting,.
I have read concerns about WebSockets and battery life but if I use GCM to turn on the WebSockets only when the user has a new message to respond to, is this a viable solution to allow real time chatting?
No I don't think so .GCM are not 100% reliable.
Their documentation says:
GCM usually delivers messages immediately after they are sent. However, this might not always be possible. For example, if the platform is Android, the device could be turned off, offline, or otherwise unavailable. Or the sender itself might request that messages not be delivered until the device becomes active by using the delay_while_idle flag. Finally, GCM might intentionally delay messages to prevent an application from consuming excessive resources and negatively impacting battery life.
When this happens, GCM will store the message and deliver it as soon as it's feasible. While this is fine in most cases, there are some applications for which a late message might as well never be delivered. For example, if the message is an incoming call or video chat notification, it will only be meaningful for a small period of time before the call is terminated. Or if the message is an invitation to an event, it will be useless if received after the event has ended.
So you can use GCM to reconnect to the webSockets if the client is not connected,but once the connection is made ,then all the communication should be on the socket itself.
I cannot use GCM and I am looking for solutions to support Push service in my application.
I saw PPNS from Parse.com and I am now using it. I starts a consistent websocket connection and checks the connection every 15min. And it also checks it on every device wake-up.
What is the approximate battery impact of just this PushService system?
Is anyone using it and tested it?
TL;DR: That's how push notification works. Don't worry about the battery usage if it's a required feature in your app.
Long version:
From what I understand (and indeed, have developed on my own App using my own MQ), that's what most/all other APIs that handle push notifications do, i.e. they maintain a persistent connection to an MQ of sorts (ActiveMQ, MSMQ, etc.) and subscribe to a specific topic which "pushes" messages to clients.
All of them require a WakeLock in order to keep this connection live in the event the phone is "sleeping" or network connection is recovered in order to make sure notifications are delivered. Some of them even maintain some level of persistence in case a message arrives when connection is lost so that they can playback the messages when they reconnect (although this would be an expensive feature in terms of server resources).
Your users most likely already have a WakeLock in one/many of their installed apps (WhatsApp, Skype, etc. -- You can check this by looking at the permissions WhatsApp requires for instance. One of them would be "preventing the phone from sleeping").
This in turn means that adding an extra WakeLock will have no material effect as the phone never REALLY goes to complete sleep anyway. If yours is the only app that has this WakeLock, then there would be a real cost to the battery but it's unavoidable unless you make sure you persist messages in the queue and only display notifications when the user unlocks the phone which is (1) expensive to maintain on your queue and (2) not very convenient as the user will miss notifications unless they're already actively using the phone so background notifications will go amiss.
I also don't imagine battery life would be hugely impacted if you're simply pinging the server every 15 minutes or so (the interval is usually the keep-alive time for the underlying message queue).
This link should help you understand how a local implementation for messaging works and should give you an idea why the ping is necessary and why you would want to maintain that WakeLock:
http://dalelane.co.uk/blog/?p=1599
edit: added TL;DR
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
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