15

I've setup an Android app with GCM support, and have a little test app to send a msg to the app. When I run the App in the emulator, I can see (via logging msgs) that it registers with GCM and gets a Token.

Then when I put the token in my test app and have it send a msg, the result shows that 1 msg was sent, 0 failed, and 0 had ID changes.

Sometimes the msg shows up almost immediately, sometimes it takes 20 minutes. On Friday, my 2 test msgs took 15 and 20 minutes. The first 2 I sent this morning were immediately, the next one hasn't shown up yet - it's only been 10 minutes...

Is there anything I can do to make the delivery times consistently fast? A random 20 minute delay will be pretty much an unacceptable condition.

CasaDelGato
  • 1,263
  • 1
  • 12
  • 29
  • 1
    I've noticed this behaviour as well and I think it is some sort of 10 minute timeout when connected via Wi-Fi. I've posted on the Google Group about it, but so far no response: https://groups.google.com/d/msg/android-gcm/Y33c9ib54jY/vmJRFv0SmKYJ – Rupert Rawnsley Nov 18 '12 at 14:49

5 Answers5

29

We had the same problem, but it varied from network-to-network. We think it was the home hub router (a Virgin Super Hub) dropping the connection after five minutes of inactivity. You can confirm by sending an empty GCM message every two minutes to keep the connection alive.

Here is a more in-depth explanation of what we did: https://groups.google.com/d/msg/android-gcm/Y33c9ib54jY/YxnCkaPRHRQJ

Rupert Rawnsley
  • 2,622
  • 1
  • 29
  • 40
  • 2
    Rupert Rawnsley, you have done some brilliant research of the GCM latency problem, that you have published in Google Group link above. This should be upvoted more – HitOdessit May 01 '13 at 13:28
4

You cannot guarantee fast delivery because GCM to device connectivity may be poor as CommonsWare has pointed out. There are however, two possible delays in the delivery train: 1) GCM connecting to the phone (as mentioned previously) and 2) The delay in the message actually being sent out from the GCM server. If you set the 'time_to_live' parameter to 0 seconds in your sending application, then you can at least test where the delay is occurring.

A value of 0 seconds means that the message will be sent immediately and if delivery is unsuccessful, the message will be discarded on the GCM server. It is not a practical value for real life use, but will enable you to find out which part of the delivery train is causing the delay.

NickT
  • 23,844
  • 11
  • 78
  • 121
  • Since I have logging on our Server around the calls to send the msg to GCM, this would mainly tell me if GCM is having problems connecting to the device, correct? I'll have to try that. – CasaDelGato Oct 23 '12 at 15:44
  • Yes with TTL at 0, if the phone doesn't get the message immediately, then the GCM server has no connection to the phone. It will then give up and never try to send the message again. – NickT Oct 23 '12 at 16:14
  • 2
    Testing with TTL=0 and TTL=1day hasn't made any difference. Sometimes the msg shows up immediately, sometimes it takes a LONG time. (Well, with TTL=0, the msg may just never show up.) Having random 15-20 minute delays, when the device IS online and active, makes GCM seem rather unreliable, and an EXTREMELY poor user experience. (Do you think somebody doing text msging wouldn't mind his msg taking 20 minutes to arrive?) – CasaDelGato Oct 23 '12 at 21:51
  • I get immediate delivery where the data connection is good. Last weekend when data conn was poor (in a different location from London) it took many minutes. On my device if I disabled packet data, then re-enabled it straight away, the messages then all came through immediately. I put this down to a bug in my Galaxy S2 switching protocols from H+ to H to 3G – NickT Oct 23 '12 at 22:28
  • Another thing to notice aside from TTL is the parameter "delay_while_idle" set on the GCM notification when posted to GCM servers. This will make it so that Google only delivers the notification once the device has come out of an idle state. – Roberto Andrade Jan 09 '14 at 23:57
4

This is indeed caused by unrealistic heartbeat intervals in Google Cloud Messaging.

This is possibly the most frustrating bug in GCM. GCM works by maintaining an idle socket connection from an Android device to Google’s servers. This is great because it barely consumes battery power (contrary to polling), and it allows the device to be woken up instantly when a message arrives. To make sure that the connection remains active, Android will send a heartbeat every 28 minutes on mobile connection and every 15 minutes on WiFi. If the heartbeat failed, the connection has been terminated, and GCM will re-establish it and attempt to retrieve any pending push notifications. The higher the heartbeat interval, the less battery consumed and the less times the device has to be woken up from sleep.

However, this comes at a great price: the longer the heartbeat interval, the longer it takes to identify a broken socket connection. Google has not tested these intervals in real-life situations thoroughly enough before deploying GCM. The problem with these intervals is caused by network routers and mobile carriers, who disconnect idle socket connections after a few minutes of inactivity. Usually, this is more common with cheap home routers, whose manufacturers decided on a maximum lifespan of an idle socket connection, and terminate it to save resources. These routers can only handle a finite number of concurrent connections, and so this measure is taken to prevent overload. This results in terminated GCM sockets, and when the time comes to deliver a GCM message, it does not reach the device. The device will only realize that the connection has been broken when it’s time to send a heartbeat, 0 – 28 minutes later, rendering the push notification useless in some situations (when the message is time-critical, for example). In my experience, most cheap routers terminate idle connections after about 5 – 10 minutes of inactivity.

I wrote an entire post about this and other GCM issues:

http://eladnava.com/google-cloud-messaging-extremely-unreliable/

An Alternative to Google Cloud Messaging

Pushy (https://pushy.me/) is a standalone push notification gateway, completely independent of GCM. It maintains its own background socket connection, just like GCM, to receive push notifications. The underlying protocol is MQTT, an extremely light-weight pub/sub protocol, utilizing very little network bandwidth and battery.

A huge advantage of Pushy is that the code for sending a push notification (from the server), and registering the device for push notifications, is actually interchangeable between GCM and Pushy. This makes it super easy to switch to Pushy after implementing GCM and having to ditch it for its instability.

(Full disclosure: I founded Pushy for my own projects and realized many apps would benefit from such a service)

Elad Nava
  • 7,746
  • 2
  • 41
  • 61
2

GCM is reportedly having a pretty severe problem with keep-alive heartbeat not being so reliable. Therefore, since it's only dispatched once every 15 minutes (over 3G) or 28 minutes (over Wifi), if for some reason the server connection is dropped, it may not be restored for several long minutes.

These type of shenanigans prompted developing a solution that does not rely on a 3rd-party network to deliver massively-scalable and reliable push notifications to offline (backgrounded) Android apps.

https://help.pubnub.com/entries/21720011-Can-my-Android-App-Receive-Messages-While-Inactive

0

This matter is important to me.

I have set up this code inside a one second timer Handler to send out a GCM message every 2 minutes. The hope is that it will keep things alive

            if ((mOneSecondTick %120) == 0){
            // q 1 minute check when we got last call....
            long lDiff = System.currentTimeMillis() - GCMlastCall;
            if (PushAndroidActivity.GCMAvailable){
                Log.d("pushAndroidActivity",String.format("(mOneSecondTick %d",lDiff));
                if (lDiff > 122 * 1000){ // more than a minute
                    Intent intent = new Intent(StayInTouch.this,PushAndroidActivity.class);
                    2startActivity(intent);
                }else{ // every 2 minutes send out a gcm message...
                    asyncWebCall(String.format(AgeingLib.GCMTICKLE,androidid),0);
                    return; // only if it sends a tickle and all is well...
                }
            }else{
                Log.d("pushAndroidActivity",String.format("(mOneSecondTick mod60 no GCM on this device"));
            }
        }

GCMlastCall is the last time a message was received, so we can tell if gcm stopped.

Been working for a couple of days now seems OK

user462990
  • 5,472
  • 3
  • 33
  • 35