Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trouble keeping Google Cloud Message alive

I am trying to work around the gcm time out issue, there are many threads on this subject, here is one for reference.

A proposed workaround is to broadcast a pair of intents at an interval shorter than the tcp timeout.

My implementation is to create a class that extends the CountDownTimer class and hold an instance of that class in an existing service. This derived class restarts itself when it is finished and the service is marked as STICKY_START, so once started, I would think it should just keep broadcasting the intents every 4 minutes, but for some reason there are gaps, when the counter does not broadcast the intents and I still loose contact with the GCM server.

The two relevant classes are below. Can anyone explain and offer a solution as to why this strategy does not work?

I created a class that extends CounDownTimer that should broadcast the intents every 4 minutes.

public class GcmKeepAlive extends CountDownTimer {

    protected CountDownTimer timer;
    protected Context mContext;
    protected Intent gTalkHeartBeatIntent;
    protected Intent mcsHeartBeatIntent;


    public GcmKeepAlive(Context context) {
        super(4*60* 1000,4*60*1000);
        mContext = context;
        gTalkHeartBeatIntent = new Intent("com.google.android.intent.action.GTALK_HEARTBEAT");
        mcsHeartBeatIntent = new Intent("com.google.android.intent.action.MCS_HEARTBEAT");
        System.out.println("stariing heartbeat countdown timer");
        this.start();
    }


    @Override
    public void onTick(long millisUntilFinished) {

    }

    @Override
    public void onFinish() {
        System.out.println("sending heart beat to keep gcm alive");
        mContext.sendBroadcast(gTalkHeartBeatIntent);
        mContext.sendBroadcast(mcsHeartBeatIntent);
        this.start();

    }

}

here is the service in my app that holds an instance of the GcmKeepAlive class

import android.app.Service; import android.content.Intent; import android.os.IBinder;

public class LocationMonitorService extends Service {

    private DeviceLocationClient deviceLocationClient;
    private GcmKeepAlive gcmKeepAlive;

    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();
        System.out.println("creating the LocationMonitorService");
        deviceLocationClient = new DeviceLocationClient(this);
        gcmKeepAlive = new GcmKeepAlive(this);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // TODO Auto-generated method stub
        System.out.println("inside service making request for location updates");
        deviceLocationClient.requestLLocationUpdates();
        gcmKeepAlive.start();
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }


}

Here is an example of a gap as seen in logcat.

07-13 14:59:05.583 I/System.out(21651): sending heart beat to keep gcm alive
07-13 15:03:05.640 I/System.out(21651): sending heart beat to keep gcm alive
07-13 15:07:05.776 I/System.out(21651): sending heart beat to keep gcm alive
07-13 15:11:05.922 I/System.out(21651): sending heart beat to keep gcm alive
07-13 15:27:31.994 I/System.out(21651): sending heart beat to keep gcm alive
like image 759
nPn Avatar asked Jul 13 '14 19:07

nPn


People also ask

How does Google Cloud Messaging work?

PRO TIP: Google Cloud Messaging for Android (GCM) is a service that allows developers to send data from their servers to their users' devices, and vice versa. GCM is completely free, and you can use it to send or receive any data, up to 4kb in size. You can then add recipients, recipients' addresses, and messages.

What is a dead letter in a Pub sub services?

Dead-letter topic Maximum number of delivery attempts: A numeric value that signifies the number of delivery attempts that Pub/Sub makes for a specific message. If the subscriber client cannot acknowledge the message within the configured number of delivery attempts, the message is forwarded to a dead-letter topic.

How do I open a ticket with Google cloud?

Go to the Google Cloud Support Center. Click New Case for the product you want to file a support ticket for. Provide required information and click Submit to create a support ticket.


1 Answers

I actually solved this some time ago, Erik Z's recent comment remained me to post my solution.

I solved this by creating a recurring alarm that triggers a broadcast, which creates and broadcasts the intents. The gaps were caused by the original service being killed and then restarted as a result of the START_STICKY flag.

Here are the various parts (pulled from various files)

This was needed pre-kitkat at the very least, I don't know if it is still needed, I assume it is. I have not turned it off to confirm however.


The alarm manager, intent , and pending intent.

AlarmManager alarmManager = (AlarmManager) Context.getSystemService(Context.ALARM_SERVICE);

Intent gcmKeepAliveIntent = new Intent("com.gmail.npnster.ourlatitude.gcmKeepAlive");

PendingIntent gcmKeepAlivePendingIntent = PendingIntent.getBroadcast(mContext, 0, gcmKeepAliveIntent, PendingIntent.FLAG_CANCEL_CURRENT);

alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, 4*60*1000, gcmKeepAlivePendingIntent);

The broadcast receiver:

public class GcmKeepAliveBroadcastReceiver extends BroadcastReceiver {

    private GcmKeepAlive gcmKeepAlive;

    @Override
    public void onReceive(Context context, Intent intent) {
        MyLog.p(this,"inside gcm keep alive receiver");
        gcmKeepAlive = new GcmKeepAlive(context);
        gcmKeepAlive.broadcastIntents();

    }

}

The keep alive class that sends the keep alive broadcasts.

public class GcmKeepAlive  {

    protected Context mContext;
    protected Intent gTalkHeartBeatIntent;
    protected Intent mcsHeartBeatIntent;

    public GcmKeepAlive(Context context) {
        mContext = context;
        gTalkHeartBeatIntent = new Intent(
                "com.google.android.intent.action.GTALK_HEARTBEAT");
        mcsHeartBeatIntent = new Intent(
                "com.google.android.intent.action.MCS_HEARTBEAT");  
    }

    public void broadcastIntents() {
        MyLog.p(this,"sending heart beat to keep gcm alive");
        mContext.sendBroadcast(gTalkHeartBeatIntent);
        mContext.sendBroadcast(mcsHeartBeatIntent);
    }

}
like image 99
nPn Avatar answered Sep 27 '22 20:09

nPn