Persistent connection with aSmack on Android

Hello,

i am trying to implement a persistant XMPP connection using aSmack. I came upon a few problems.

What i have so far:

I create a new TCPConnection with PingManager(every 10s) in a Thread in my foreground serivce. setReconnectionAllowed ist true.

I noticed that after some random time the connection fails. I think this is beacause the CPU goes into sleep mode, shouldn’t the PingManager/KeepAliveManager handle this for me?

I haven’t tried pinging the server manualy using Androids AlarmManager which should wake the CPU for me yet.

Looking at the Xabber src(they bring their own smack fork) i saw a loop using a Handler and postDelayed in their code, checking if the connection is alive every second and reconnecting if it is not - without wakelocks as far as i can tell(turned of in settings).

Any hints how to implement a “persistant connection” the best way on Android? Aquireing wakelocks should work, but i think that is a very bad solution.

Some other useful information: Phone is a Nexus 4 with KitKat and i am developing for ICS and newer.

Thanks and and i know my english isn’t the best

Prevent the phone from sleeping. This is likely not in the xmpp code but in the app permissions.

If the phone starts saving energy it may turn off WiFi and data, so one may want to control/listen to these settings/state changes.

Anyhow an Android forum may produce better answers. Maybe with 4.x there are better down-/upload features.

Wakelooks, preventing the phone from sleeping are obviously a bad idea, if you don’t want to build a battery draining app.

I can only point to MAXS Transport XMPP as reference implementation how a persistent connection is done correctly.

Standard Android implementations do not turn off Wifi when the device get’s into sleep. But this can vary between manufactures and (custom) ROMs. I even have reports from (terrible IMHO) implementations that close the socket in certain situations.

When it comes to mobile XMPP, you will always have to make a tradeoff between battery consumption and connection stability. For example, sending a Ping every 10 seconds may assures that a broken connection is detected in a short timeframe, but the short inverall cause increased battery consumption, because the radio or WiFi adapter needs to become active and is prevent from going in power saving mode. That’s why I would never recommend a ping interval lower then 15 minutes. In fact I recommend 30 minutes.

Since you didn’t say why the conneciton when down, it’s hard to give further advice.

I think i can divide the problem in 2 problems now. The first is the cpu going to sleep for a too long time sometimes causing timeouts on the server i think. I think i can resolve this by waking the device up and sending ping at the max time before the server times out.

My second problem is reconnecting when i detect a broken connection. I think the internal reconnectionmanager from smack is not very suitable for android. While the ReconnectionManager loops the cpu goes into sleep again and stops smack from reconnecting.

Together with the first problem: If the cpu starts working again after the server got a timeout because the connection was idle for too long and smack tries to go on with reconnection i got this:

org.jivesoftware.smack.SASLAuthentication.authenticate(SASLAuthentication.java:3 52)

org.jivesoftware.smack.TCPConnection.login(TCPConnection.java:236)

org.jivesoftware.smack.TCPConnection.connect(TCPConnection.java:883)

Saw this only 1 or 2 time a week testing my code. Don’t have any more logs then that.

Solution for the second problem seems to disable the ReconnectionManager and do the reconnection attempts with the AlarmManager. I don’t know if it is reasonable to integrate a special reconnection mechanism for android in smack itself?

Another small question on the side, is there anything to read about using XMPP extensions with smack? I am interested in message carbons.

Another thing i noticed is, if i type emoji smilies with the stock android keyboard (hold return) the connection goes down without any exceptions.

The first is the cpu going to sleep for a too long time sometimes causing timeouts on the server i think.

Possible, the key aspects here are

  • The TCP connection should have a long timeout of (min(s2cPingInterval, c2sPingInterval) + 30min)

  • The server should have a long grace period where it awaits Pongs from the client. If an Android device is in sleep, the Ping-Pong lag can be sometimes around 5-10 minutes

I think i can resolve this by waking the device up and sending ping at the max time before the server times out.

You usually want to avoid that at all costs. Instead identify the exact reason the connection is terminated (e.g. is it the server? On XMPP or TCP layer?) and take appropriate countermeasures (like the one mentioned above).

. I think the internal reconnectionmanager from smack is not very suitable for android.

Right, I also recommend to disable the ReconnectionManager on Android. Of course this means that you have to implement your own reconnection logic and you need to know what you are doing.

While the ReconnectionManager loops the cpu goes into sleep again and stops smack from reconnecting.

This is not my obersvation. I test on stock ROMs and Cyanogenmod. The CPU is never completly shut off and TCP sockets are not closed. Everything just takes longer in terms of minutes instead of seconds.

org.jivesoftware.smack.SASLAuthentication.authenticate(SASLAuthentication.java:3 52)

org.jivesoftware.smack.TCPConnection.login(TCPConnection.java:236)

org.jivesoftware.smack.TCPConnection.connect(TCPConnection.java:883)

It’s hard to tell what’s going on there without knowing at least the Exception and the used aSmack version. I appreciate that you striped away unecessary information, but the Exception Typ would have been helpfull here.

Solution for the second problem seems to disable the ReconnectionManager and do the reconnection attempts with the AlarmManager.

If you really need to wake up the device to ensure are more responsive connection (not sure if this is really your use case), then AlarmManager is the way to go.

I don’t know if it is reasonable to integrate a special reconnection mechanism for android in smack itself?

Smack, especially the newer versions. Provide callbacks to inform the user about state changes of the XMPPConnection. You can easly implement your own reconnection logic on top of that. In fact, that is what MAXS does.

Another thing i noticed is, if i type emoji smilies with the stock android keyboard (hold return) the connection goes down without any exceptions.

I doubt that a connection in Smack can go down without any callbacks involved. What likely happens ist that the server closes the stream because it thinks the emojis are not allowed in the stream. In that case, Smack would invoke the connectionClosedOnError(Exception) callback with a “socket closed” Exception or the like.

1 Like

Thanks for your answers I will investigate the issues further and post more details here later.

I am using yesterdays asmack snapshot linked in the git readme, the server is based on openfire(not the newest version at the moment).

I also will push my latest code to github later.

Longterm we are considering using both gcm and xmpp but for the moment i need a relativly stable connection like xabber does.

+1 for using the Snapshots. :slight_smile:

I guess you are aware of the nature of Snapshot releases. They are not intensivly tested, but as more people use them as sooner we can react on possible bugs or regressions.

Yes, i am fully aware of the nature of Snapshots :slight_smile:

Is AndroidConnectionConfiguration no longer needed? Using normal Configuration class now.

Emoji:

SENT (0): (the emoji)c922a174-4c1f-48ac-81af-e7d77f2c9712

RCV (0): </stream:stream>

SENT (0):

Connection closed (0)

ConnectionListener.connectionClosed() called

Thats what i get sending emojis, but chat.sendMessage(message); doesn’t throw an exception. I think, the server just closes the connection right after sending as you said before. Going to test this with a fresh install of Openfire.

EDIT: Tested it with Xabber, got the same Result. So either this is a Smack limitation or more likely a server limitation.

SleepMode:

But it is inrcedibly annoying in my opinion if the reconnection process takes an hour instead of a few seconds.

Testing my own ReconnectionManager using AlarmManager right now.

Got information of the openfire configuration a few seconds ago :slight_smile:

xmpp.client.idle -1 xmpp.client.idle.ping true

Never saw any pings coming from the server in logcat, only pongs if i start pinging. I dont think this is correct looking at the config above.

I think, the server just closes the connection right after sending as you said before.
Well, what do the server logs tell you? (you maybe have to enable Openfire’s debug log)

Server is not maintained by me so i have to wait. But i am going to install a local openfire server later.

Does Openfire send pings as described here http://www.xmpp.org/extensions/xep-0199.html#s2c or do we use c2s pings?

I read that an incoming packet can wakeup Android, then one needs to acquire a wakelock to send the pong and release the wakelock.

http://stackoverflow.com/questions/13534732/how-to-make-the-android-device-hold- a-tcp-connection-to-internet-without-wake-lo

IIRC Openfires uses XMPP pings (xep-199). Not sure what you mean with c2s pings.

I read that an incoming packet can wakeup Android, then one needs to acquire a wakelock to send the pong and release the wakelock.
This is not my experience with sleeping devices, for all versions I’ve ever worked with (should be from 2.2. on). You can certainly send a reply back without a wakelock.

In GTalkSMS we aquire a wakelock, because I hoped that it would increase responsiveness, but this was not the caseu. That’s why I don’t do it in MAXS any more.

C2s - client sends ping, server replies with pong.

I’d add at least a user option to use wakelocks. An alarm which is triggered if no ping was received should also be added - one should update the trigger time on every ping/pong.

I’ve to correct my statement, as I just made a similar experience with openfire and unicode emojis from a range that is greater then 0xFFFF, for example 0x1F634: Prior r13995 openfire would simply cleanly close the connection if such a code point was detected in the XML stream. This is wrong because

  • Suche code points are allowed in XMPP streams

  • Even if not, openfire should terminate the connection with a stream error, so that Smack’s connectionClosedOnError callback is invoked

This was not the case, therefore Smack went silently to the disconnected state, without informing the application about it.

I’ve fixed that now, starting with todays trunk, openfire is able to process the valid unicode stanzas, and this includes the emojis defined in unicode, correctly.

1 Like

That sounds nice, thanks for fixing the bug this fast

Late update but i found something interesting…

My problem is that something like this is happened to my app:

https://code.google.com/p/android/issues/detail?id=53313#c1