0

I have an app which connects to XMPP. Every 5 minutes I disconnect and reconnect (don't ask, boss wanted it...) - Up until now I've had an AsyncTask to do this in the background and it's been running fine. Today, however, is a different story (bear in mind that the code hasn't changed for quite some time! And is SC'd via SVN, I've checked that no changes have happened since the last release).

Today it'll disconnect and start the connection after 5 minutes, but only after a reboot. Any subsequent attempts don't even bother to try.

The runnable that reconnects:

private final Runnable killConnection = new Runnable()
{
    @Override
    public void run()
    {
        synchronized(checkLock)
        {
            Log.d("BXC", "Killing connection and restarting");

            // Manually disconnect and restart the connection every 5 minutes
            destroyConnectionAndRestart();
            new LoginTask().execute();

            mHandler.postDelayed(this, mInterval5m);
        }
    }
};

And the AsynTask itself:

private class LoginTask extends AsyncTask<Void, Void, Void>
{
    @Override
    protected Void doInBackground(Void... params)
    {
        android.os.Debug.waitForDebugger();

        String deviceUsername = Utility.getAndroidID(GaggleApplication.getInstance());
        try
        {   
                //bConnecting = true;
                Log.d("BXC", "Beginning connection");
                synchronized(connectLock)
                {                   
                    // First ensure we've got a connection to work with first
                    if(Utility.hasActiveInternetConnection(getApplicationContext()) && 
                            ((!bConnecting) && (!Globals.backgroundXmppConnectorRunning)))
                    {                       
                        String randomResource = Utility.randomString();
                        setupConnection();

                        if(xConnection != null)
                        {
                            xConnection.connect();
                        }
                        else
                        {
                            bConnecting = false;
                            Globals.backgroundXmppConnectorRunning = false;
                            setupConnection();
                            xConnection.connect();
                        }

                        /*
                            I know, I know... Don't specify a resource, but more often than not, OpenFire, doesn't
                            specify a unique resource, so at least this way, if we disconnect and then reconnect, 
                            we're at least promised a resource that isn't being used already and leave OpenFire to 
                            remove it's own idle connections, after X minutes.
                         */                             
                        if(accountManager.supportsAccountCreation() && (!SystemProperties.getBoolean("accountCreated")))
                        {
                            Log.d("BXC", "Server supports registering custom user accounts");
                            accountManager.createAccount(deviceUsername, AppSettings.XMPP_KEYSTORE_PASSWORD);   
                            SystemProperties.setBoolean("accountCreated", true);
                        }

                        xConnection.login(deviceUsername, AppSettings.XMPP_KEYSTORE_PASSWORD, randomResource);                  
                        ChatManager.getInstanceFor(xConnection).addChatListener(new ChatManagerListener(){
                            @Override
                            public void chatCreated(final Chat chat, boolean createdLocally)
                            {
                                if(!createdLocally)
                                {
                                    // add chat listener //
                                    chat.addMessageListener(new BackgroundMessageListener(BackgroundXmppConnector.this));
                                }
                            }                           
                        });                 

                        Presence p = new Presence(Presence.Type.subscribe);
                        p.setStatus("Out and About");
                        xConnection.sendPacket(p);

                        mBuilder.setSmallIcon(android.R.drawable.presence_online)
                        .setContentTitle("Connected")
                        .setContentText("Connected to XMPP server");

                        mNotificationManager.notify(mNotificationId, mBuilder.build());

                        Roster r = xConnection.getRoster();                 
                        r.setSubscriptionMode(SubscriptionMode.accept_all);
                        r.createEntry(AppSettings.BOT_NAME, "AbleBot", null);
                        r.addRosterListener(new RosterListener(){

                            @Override
                            public void entriesAdded(Collection<String> addresses) 
                            {               
                                for(String s : addresses)
                                {
                                    Log.d("BXC", "Entries Added: " + s);
                                }
                            }

                            @Override
                            public void entriesDeleted(Collection<String> addresses) 
                            {
                                for(String s : addresses)
                                {
                                    Log.d("BXC", "Entries Deleted: " + s);
                                }                           
                            }

                            @Override
                            public void entriesUpdated(Collection<String> addresses) 
                            {   
                                for(String s : addresses)
                                {
                                    Log.d("BXC", "Entries updated: " + s);
                                }                           
                            }

                            @Override
                            public void presenceChanged(Presence presence) 
                            {   
                                Log.d("BXC", "PresenceChanged: " + presence.getFrom());
                            }                       
                        });
                    }   
                    else{
                        Log.i("BXC", "Already connected or in process of connecting. ");
                    }
            }
        }
        catch(IllegalStateException ex)
        {
            Log.e("BXC", "IllegalStateException -->");
            if(ex.getMessage().contains("Already logged in to server"))
            {
                Globals.backgroundXmppConnectorRunning = true;                      
            }
            else
            {
                Globals.backgroundXmppConnectorRunning = false;
                Utility.writeExceptionToLog(getApplicationContext(), ex);

                ex.printStackTrace();
            }
        }
        catch(XMPPException ex)
        {
            Log.e("BXC", "XMPPException -->");
            Globals.backgroundXmppConnectorRunning = false;
            Utility.writeExceptionToLog(getApplicationContext(), ex);
            ex.printStackTrace();
        }
        catch(NullPointerException ex)
        {
            Log.e("BXC", "NullPointerException -->");
            Globals.backgroundXmppConnectorRunning = false;
            Utility.writeExceptionToLog(getApplicationContext(), ex);
            ex.printStackTrace();
        }
        catch(Exception ex)
        {
            Log.e("BXC", "Exception -->");
            Globals.backgroundXmppConnectorRunning = false;
            Utility.writeToLog(getApplicationContext(), ex.toString());
            ex.printStackTrace();
        }               
        return null;
    }

    @Override
    protected void onPostExecute(Void ignored)
    {
        if(xConnection != null)
        {
            if(xConnection.isConnected() && (!xConnection.isSocketClosed()))
            {
                Log.i("BXC", "Logged in to XMPP Server");
                Globals.backgroundXmppConnectorRunning = true;

                ConnectionState cs = new ConnectionState(true);
                GaggleApplication.getBusInstance().post(cs);
                cs = null;

                // SEND A WHOAMI TO UPDATE DEVICE FRIENDLY NAME //
                WhoAmI wai = new WhoAmI();          
                Intent intent = new Intent(GaggleApplication.getInstance(), BackgroundXmppConnector.class);
                intent.putExtra("MESSAGEDATA", new Gson().toJson(
                        Utility.makeTransaction(GaggleApplication.getInstance(), MessageType.Type.WHOAMI, wai)));
                sendMessage(intent);
                Log.i("MAIN", "Sent WHOAMI transaction");                   

                mHandler.postDelayed(checkConnection, mInterval1m);
            }
            else
            {
                Log.e("BXC", "Unable to log into XMPP Server.");    
                Globals.backgroundXmppConnectorRunning = false;

                destroyConnectionAndRestart();
            }
        }
        else
        {
            Log.e("BXC", "Xmpp Connection object is null");
            Globals.backgroundXmppConnectorRunning = false;

            ConnectionState cs = new ConnectionState(false);
            GaggleApplication.getBusInstance().post(cs);
            cs = null;
        }
    }
}

I've tried debugging with the help of this SO post: How do I use the Eclipse debugger in an AsyncTask when developing for Android? - And as described above, any subsequent attempts don't fire the doInBackground - There is nothing of any relevance in LogCat either, I'm a little lost.

If anyone has experienced this before, any help is greatly appreciated?

Community
  • 1
  • 1
laminatefish
  • 5,197
  • 5
  • 38
  • 70
  • 1
    You need to debug step by step and determine the line where it hangs. Most of all you have synchronization deadlock somewhere but not sure. – Eugene Popovich Oct 09 '14 at 11:55
  • Have done that. Upon entering the AsyncTask, it immediately leaves. Doesn't even touch the doInBackground, nor the onPostExecute. I'll check for a sync clash though. – laminatefish Oct 09 '14 at 11:58
  • By default AsyncTask uses SerialExecutor. If previous AsyncTask.doInBackground was not finished it will not start second execution. You need to find out why the first call is never finished – Eugene Popovich Oct 09 '14 at 12:03
  • also i do not have any problems with debugging of doInBackground methods. Don't need to use android.os.Debug.waitForDebugger() – Eugene Popovich Oct 09 '14 at 12:08
  • Check if you've added another AsyncTasks recently which has long running operations in the doInBackground. – Eugene Popovich Oct 09 '14 at 12:14

1 Answers1

0

Try this way, It's working for me.

public void createXMPPConn() {
        Log.i(TAG, "creating connection");
        if (!NetworkUtil.isNetworkAvailable(getApplicationContext())) {
            return;
        }

        Thread conn = new Thread(new Runnable() {

            private String mPwd;

            @Override
            public void run() {
                do {
                    Log.i(TAG, "Trying to create connection");
                    try {
                        ConnectionConfiguration config = new ConnectionConfiguration(URLConstants.XMPP_HOST,
                                URLConstants.XMPP_PORT);
                        config.setSASLAuthenticationEnabled(false);
                        config.setSecurityMode(SecurityMode.disabled);
                        mXMPPCon = new XMPPConnection(config);
                        mPwd = csp.getString(StringConstants.PASSWORD, "");

                        mXMPPCon.connect();
                        Log.i(TAG, "Connected ");
                        if (!mPwd.equals("") && !mXMPPCon.isAuthenticated()) {
                            mXMPPCon.login(csp.getString(StringConstants.PHONE_NUMBER, ""), mPwd);
                            initIncomingChat(getApplicationContext());
                            setStatus(getmXMPPCon(), true, "");
                            sendBroadCastAsLoginSuccess();
                        }

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // Rotate loop until app is not connected to XMPP and do
                    // login, if app is registered.

                } while (!mXMPPCon.isConnected() && !(mPwd.equals("") || mXMPPCon.isAuthenticated()));
            }

        });
        conn.start();

}

public void login(final XMPPConnection xmppCon, final IAuthenticationListener iAuthenticationListener,
            final String username, final String password) {

        Log.i(TAG, "login() " + username + " " + password);

        Thread loginThread = new Thread(new Runnable() {

            @Override
            public void run() {
                Looper.prepare();
                try {
                    xmppCon.login(username, password);
                    Log.i(TAG, "LOGIN SUCCESS");
                    sendLoginSuccess(iAuthenticationListener);

                } catch (XMPPException e) {
                    Log.i(TAG, e.getMessage());
                    if (e.getXMPPError() != null && e.getXMPPError().getCode() == ErrorConstants.ERROR_SERVERDOWN) {

                    } else if (e.getXMPPError() != null
                            && e.getXMPPError().getCode() == ErrorConstants.ERROR_NOTCONNECTED) {

                    } else {

                    }
                    Log.i(TAG, "LOGIN FAILURE");
                    sendLoginFailure(iAuthenticationListener);

                } catch (IllegalStateException e) {
                    if (xmppCon.isAuthenticated()) {
                        sendLoginSuccess(iAuthenticationListener);
                    } else {
                        e.printStackTrace();
                        sendLoginFailure(iAuthenticationListener);
                    }
                }
                Looper.loop();
                try {
                    Thread.currentThread().join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        });
        loginThread.start();

    }
samsad
  • 1,241
  • 1
  • 10
  • 15
  • Thank you but the connection isn't the problem. This has been working wonderfully for months. – laminatefish Oct 09 '14 at 12:10
  • Hi @LokiSinclair, I hope you are using openFire, Openfire admin portal have option to set connection time out (like 5 min, 10 min and lifetime etc) :) – samsad Oct 09 '14 at 13:40