aTalk is experiencing a long pause of ~40 seconds in start of sending the <stream/> login stanza after XMPPConnection#connect() is called (see aTalk logcat below). This problem occurs occasionally but persisted. Sometimes the problem recovers itself after some few hours of no debug activity. Previously the problem also recovers after I restart my android Note-10, but this seems to be not 100% all the time recently.
Under normal login process, this delay is <100ms; see 2nd aTalk logcat capture
Earlier I was doubting whether
accountAuthenticated.checkIfSuccessOrWait();
in connectAndLogin() call is holding back smack process execution, but has verified this is no the case.
I have raised the issue with android SDK development team since Sep 26, 2021, suspecting it may be due to AS adb debug or OS garbage collection, but still has not get any advice from them.
Google Issue Tracker (Please ignore the issue title)
The problem started since Smack v4.4.4 in aTalk v2.7.1 release, but not sure the problem has to do with Smack library or it is an AS adb debug problem.
Appreciate if your team can also advice on the observed problem.
======== aTalk login with long pause of 40 seconds =============
2022-06-02 08:10:16.892 16860-17062/org.atalk.android I/(ProtocolProviderServiceJabberImpl.java:1108)#connectAndLogin: Starting XMPP Connection...: atalk.sytes.net/42.60.7.13:5222
....
2022-06-02 08:10:18.812 649-649/? I/Layer: id=5853 Destroyed ActivityRecord{c37ed3a u0 org.atalk.android/.gui.LauncherActivity t77375}#0
2022-06-02 08:10:19.240 978-1056/? D/SGM:GameManager: identifyForegroundApp. org.atalk.android, mCurrentUserId: 0, callerUserId: 0
2022-06-02 08:10:19.240 978-1056/? D/SGM:PkgDataHelper: getGamePkgData(). org.atalk.android
2022-06-02 08:10:37.176 16860-17062/org.atalk.android I/aTalk: [163] org.jivesoftware.smack.tcp.rce.RemoteXmppTcpConnectionEndpoints.resolveDomain() Could not resolve DNS SRV resource records for _xmpp-client._tcp.atalk.sytes.net. Consider adding those.
### => Unexpected long pause of ~40 seconds before start of <stream/> login process
2022-06-02 08:11:17.698 16860-17110/org.atalk.android D/SMACK: SENT (0):
<stream:stream xmlns='jabber:client' to='atalk.sytes.net' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' xml:lang='en'>
2022-06-02 08:11:17.741 16860-17111/org.atalk.android D/SMACK: RECV (0): ?xml version='1.0'?>
<stream:stream id='9168948287818266291' version='1.0' xml:lang='en' xmlns:stream='http://etherx.jabber.org/streams' from='atalk.sytes.net' xmlns='jabber:client'>
<stream:features>
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'>
<required/>
</starttls>
</stream:features>
2022-06-02 08:11:17.755 16860-17110/org.atalk.android D/SMACK: SENT (0):
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
2022-06-02 08:11:17.767 16860-17111/org.atalk.android D/SMACK: RECV (0):
<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
2022-06-02 08:11:19.134 16860-17110/org.atalk.android D/SMACK: SENT (0):
<stream:stream xmlns='jabber:client' to='atalk.sytes.net' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' id='9168948287818266291' xml:lang='en'>
2022-06-02 08:11:19.147 16860-17111/org.atalk.android D/SMACK: RECV (0): ?xml version='1.0'?>
<stream:stream id='8505503090397911150' version='1.0' xml:lang='en' xmlns:stream='http://etherx.jabber.org/streams' from='atalk.sytes.net' xmlns='jabber:client'>
2022-06-02 08:11:19.157 16860-17111/org.atalk.android D/SMACK: RECV (0):
<stream:features>
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
<mechanism>
EXTERNAL
</mechanism>
<mechanism>
PLAIN
</mechanism>
<mechanism>
SCRAM-SHA-1-PLUS
</mechanism>
<mechanism>
SCRAM-SHA-1
</mechanism>
<mechanism>
X-OAUTH2
</mechanism>
</mechanisms>
<register xmlns='http://jabber.org/features/iq-register'/>
</stream:features>
2022-06-02 08:11:19.171 16860-17059/org.atalk.android W/g.atalk.androi: Long monitor contention with owner Smack DefaultReactor Thread #1 (17060) at int sun.nio.ch.SelectorImpl.lockAndDoSelect(long)(SelectorImpl.java:86) waiters=0 in void org.jivesoftware.smack.SmackReactor$Reactor.handleScheduledActionsOrPerformSelect() for 62.487s
2022-06-02 08:11:19.224 16860-17062/org.atalk.android I/(AndroidOmemoService.java:50)#<init>: ### Registered omemo messageListener for: swordfish@atalk.sytes.net
2022-06-02 08:11:19.259 16860-17062/org.atalk.android D/(ProtocolProviderServiceJabberImpl.java:1146)#connectAndLogin: Entering check IfSuccess Or Wait or Throw!
// aTalk Thread states while in 40s pause
""@25,079: ZOMBIE
"ADB-JDWP Connection Control Thread"@21,255: WAIT
"Binder:20000_1"@21,260 in group "main": RUNNING
"Binder:20000_2"@21,261 in group "main": RUNNING
"Binder:20000_3"@21,262 in group "main": RUNNING
"Binder:20000_4"@23,077 in group "main": RUNNING
"Binder:20000_5"@23,998 in group "main": RUNNING
"Binder:20000_6"@24,006 in group "main": RUNNING
"Binder:20000_7"@24,089 in group "main": RUNNING
"Binder:20000_8"@24,120 in group "main": RUNNING
"Binder:20000_9"@24,124 in group "main": RUNNING
"Chrome_IOThread"@21,674 in group "main": RUNNING
"Chrome_ProcessLauncherThread"@21,485 in group "main": RUNNING
"CleanupReference"@21,839 in group "main": WAIT
"FinalizerDaemon"@21,258: WAIT
"FinalizerWatchdogDaemon"@21,259: WAIT
"GoogleApiHandler"@21,569 in group "main": RUNNING
"HeapTaskDaemon"@21,256: WAIT
"hwuiTask0"@23,080 in group "main": RUNNING
"hwuiTask1"@23,081 in group "main": RUNNING
"Jit thread pool worker thread 0"@21,254: RUNNING
"main"@20,995 in group "main": RUNNING
"org.atalk.impl.osgi.framework.AsyncExecutor"@23,311 in group "main": WAIT
"org.atalk.impl.osgi.framework.AsyncExecutor"@23,206 in group "main": WAIT
"org.atalk.impl.osgi.framework.AsyncExecutor"@23,098 in group "main": WAIT
"PlatformServiceBridgeHandlerThread"@21,705 in group "main": RUNNING
"Profile Saver"@21,011: RUNNING
"queued-work-looper"@22,628 in group "main": RUNNING
"queued-work-looper-data"@21,014 in group "main": WAIT
"ReferenceQueueDaemon"@21,257: WAIT
"RenderThread"@22,026 in group "main": RUNNING
"Signal Catcher"@21,253: WAIT
"Smack DefaultReactor Thread #0"@26,172 in group "main": MONITOR
"Smack DefaultReactor Thread #1"@26,176 in group "main": RUNNING
"Thread-13"@26,448 in group "main": WAIT
"Thread-15"@26,767 in group "main": WAIT
"ThreadPoolForeg"@22,631 in group "main": RUNNING
"ThreadPoolForeg"@21,688 in group "main": RUNNING
"ThreadPoolSingl"@21,709 in group "main": RUNNING
"Timer-0"@25,187 in group "main": WAIT
============== aTalk normal login timing ===========
2022-05-31 08:00:05.433 26547-26659/org.atalk.android I/(ProtocolProviderServiceJabberImpl.java:979)#connectAndLogin: Connect using service SRV Resource Record: atalk.sytes.net/42.60.7.13:5222
2022-05-31 08:00:05.464 26547-26659/org.atalk.android I/(ProtocolProviderServiceJabberImpl.java:1108)#connectAndLogin: Starting XMPP Connection...: atalk.sytes.net/42.60.7.13:5222
.....
2022-05-31 08:00:05.856 26547-26659/org.atalk.android I/aTalk: [87] org.jivesoftware.smack.tcp.rce.RemoteXmppTcpConnectionEndpoints.resolveDomain() Could not resolve DNS SRV resource records for _xmpp-client._tcp.atalk.sytes.net. Consider adding those.
2022-05-31 08:00:05.925 26547-26675/org.atalk.android D/SMACK: SENT (0):
<stream:stream xmlns='jabber:client' to='atalk.sytes.net' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' xml:lang='en'>
2022-05-31 08:00:05.932 26547-26676/org.atalk.android D/SMACK: RECV (0): ?xml version='1.0'?>
<stream:stream id='16637983341418396771' version='1.0' xml:lang='en' xmlns:stream='http://etherx.jabber.org/streams' from='atalk.sytes.net' xmlns='jabber:client'>
2022-05-31 08:00:05.933 26547-26676/org.atalk.android D/SMACK: RECV (0):
<stream:features>
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'>
<required/>
</starttls>
</stream:features>
============ aTalk user login process ================
private ConnectState connectAndLogin(String userName, JabberLoginStrategy loginStrategy)
throws XMPPException, SmackException
{
ConnectionConfiguration.Builder<?, ?> config = loginStrategy.getConnectionConfigurationBuilder();
// Set XmppDomain to serviceName - default for no server-overridden and Bosh connection.
DomainBareJid serviceName = mAccountID.getXmppDomain();
config.setXmppDomain(serviceName);
config.setResource(mResource);
config.setProxyInfo(proxy);
config.setCompressionEnabled(false);
/*=== Configure connection for BOSH or TCP ===*/
boolean isBosh = mAccountID.isBOSHEnable();
if (isBosh) {
String boshURL = mAccountID.getBoshUrl();
BOSHConfiguration.Builder boshConfigurationBuilder = (BOSHConfiguration.Builder) config;
try {
URI boshURI = new URI(boshURL);
boolean useHttps = boshURI.getScheme().equals("https");
int port = boshURI.getPort();
if (port == -1) {
port = useHttps ? 443 : 80;
}
String file = boshURI.getPath();
// use rawQuery as getQuery() decodes the string
String query = boshURI.getRawQuery();
if (!TextUtils.isEmpty(query)) {
file += "?" + query;
}
boshConfigurationBuilder
.setUseHttps(useHttps)
.setFile(file)
.setHost(boshURI.getHost())
.setPort(port);
} catch (URISyntaxException e) {
Timber.e("Fail setting bosh URL in XMPPBOSHConnection configuration: %s", e.getMessage());
StanzaError stanzaError = StanzaError.getBuilder(Condition.unexpected_request).build();
throw new XMPPErrorException(null, stanzaError);
}
}
else {
/*
* The defined settings for setHostAddress and setHost are handled by XMPPTCPConnection
* #populateHostAddresses()-obsoleted, mechanism for the various service mode.
*/
boolean isServerOverridden = mAccountID.getAccountPropertyBoolean(
ProtocolProviderFactory.IS_SERVER_OVERRIDDEN, false);
// cmeng - value not defined currently for CUSTOM_XMPP_DOMAIN login
String customXMPPDomain = mAccountID.getAccountPropertyString(ProtocolProviderFactory.CUSTOM_XMPP_DOMAIN);
if (customXMPPDomain != null) {
mInetSocketAddress = new InetSocketAddress(customXMPPDomain, DEFAULT_PORT);
Timber.i("Connect using custom XMPP domain: %s", mInetSocketAddress);
config.setHostAddress(mInetSocketAddress.getAddress());
config.setPort(DEFAULT_PORT);
}
/*=== connect using overridden server name defined by user ===*/
else if (isServerOverridden) {
String host = mAccountID.getServerAddress();
int port = mAccountID.getAccountPropertyInt(ProtocolProviderFactory.SERVER_PORT, DEFAULT_PORT);
mInetSocketAddress = new InetSocketAddress(host, port);
Timber.i("Connect using server override: %s", mInetSocketAddress);
// For host given as ip address, then no DNSSEC authentication support
if (Character.digit(host.charAt(0), 16) != -1) {
config.setHostAddress(mInetSocketAddress.getAddress());
}
// setHostAddress will take priority over setHost in smack populateHostAddresses() implementation - obsoleted
config.setHost(host);
config.setPort(port);
}
/*=== connect using SRV Resource Record for userID service name (host and hostAddress must be null) ===*/
else {
mInetSocketAddress = new InetSocketAddress(mAccountID.getService(), DEFAULT_PORT);
Timber.i("Connect using service SRV Resource Record: %s", mInetSocketAddress);
config.setHost((DnsName) null);
config.setHostAddress(null);
}
}
// if we have OperationSetPersistentPresence to take care of <presence/> sending, then
// disable smack from sending the initial presence upon user authentication
OpSetPP = getOperationSet(OperationSetPersistentPresence.class);
if (OpSetPP != null)
config.setSendPresence(false);
if (mConnection != null && mConnection.isConnected()) {
Timber.w("Attempt on connection that is not null and isConnected %s", mAccountID.getAccountJid());
disconnectAndCleanConnection();
}
config.setSocketFactory(SocketFactory.getDefault());
String[] supportedProtocols = {"TLSv1", "TLSv1.1", "TLSv1.2"};
try {
supportedProtocols = ((SSLSocket) SSLSocketFactory.getDefault().createSocket()).getSupportedProtocols();
} catch (IOException e) {
Timber.d("Use default supported Protocols: %s", Arrays.toString(supportedProtocols));
// Use default list
}
Arrays.sort(supportedProtocols);
// Determine enabled TLS protocol versions using getMinimumTLSversion
ArrayList<String> enabledTLSProtocols = new ArrayList<>();
for (int prot = supportedProtocols.length - 1; prot >= 0; prot--) {
final String prot_version = supportedProtocols[prot];
enabledTLSProtocols.add(prot_version);
if (prot_version.equals(mAccountID.getMinimumTLSversion())) {
break;
}
}
String[] enabledTLSProtocolsArray = new String[enabledTLSProtocols.size()];
enabledTLSProtocols.toArray(enabledTLSProtocolsArray);
config.setEnabledSSLProtocols(enabledTLSProtocolsArray);
// Cannot use a custom SSL context with DNSSEC enabled
String dnssecMode = mAccountID.getDnssMode();
if (DNSSEC_DISABLE.equals(dnssecMode)) {
config.setDnssecMode(DnssecMode.disabled);
/*
* BOSH connection does not support TLS;
* XEP-206 Note: The client SHOULD ignore any Transport Layer Security (TLS) feature since
* BOSH channel encryption SHOULD be negotiated at the HTTP layer.
*/
boolean tlsRequired;
if (isBosh) {
tlsRequired = false;
config.setSecurityMode(SecurityMode.disabled);
}
else {
/*
* user have the possibility to disable TLS but in this case, it will not be able to
* connect to a server which requires TLS;
*/
tlsRequired = loginStrategy.isTlsRequired();
config.setSecurityMode(tlsRequired ? SecurityMode.required : SecurityMode.ifpossible);
}
CertificateService cvs = getCertificateVerificationService();
if (cvs != null) {
try {
X509TrustManager sslTrustManager = getTrustManager(cvs, serviceName);
SSLContext sslContext = loginStrategy.createSslContext(cvs, sslTrustManager);
SslContextFactory sslContextFactory = () -> sslContext;
config.setSslContextFactory(sslContextFactory);
config.setCustomX509TrustManager(sslTrustManager);
config.setAuthzid(mAccountID.getBareJid().asEntityBareJidIfPossible());
} catch (GeneralSecurityException e) {
Timber.e(e, "Error creating custom trust manager");
// StanzaError stanzaError = StanzaError.getBuilder(Condition.service_unavailable).build();
throw new ATalkXmppException("Security-Exception: Creating custom TrustManager", e);
}
}
else if (tlsRequired) {
// StanzaError stanzaError = StanzaError.getBuilder(Condition.service_unavailable).build();
// throw new XMPPErrorException(null, stanzaError);
throw new ATalkXmppException("Security-Exception: Certificate verification service is unavailable and TLS is required");
}
}
else {
if (DNSSEC_ONLY.equals(dnssecMode)) {
config.setDnssecMode(DnssecMode.needsDnssec);
}
else if (DNSSEC_AND_DANE.equals(dnssecMode)) {
// override user SecurityMode setting for DNSSEC & DANE option
config.setDnssecMode(DnssecMode.needsDnssecAndDane);
config.setSecurityMode(ConnectionConfiguration.SecurityMode.required);
}
}
// String userJid = userName + "@" + serviceName;
// String password = userCredentials.getPasswordAsString();
// config.setUsernameAndPassword(userJid, password);
try {
if (isBosh) {
mConnection = new XMPPBOSHConnection((BOSHConfiguration) config.build());
}
else {
mConnection = new XMPPTCPConnection((XMPPTCPConnectionConfiguration) config.build());
}
} catch (IllegalStateException ex) {
// Cannot use a custom SSL context with DNSSEC enabled
String errMsg = ex.getMessage() + "\n Please change DNSSEC security option accordingly.";
StanzaError stanzaError = StanzaError.from(Condition.not_allowed, errMsg).build();
throw new XMPPErrorException(null, stanzaError);
}
/* Start monitoring the status before connection-login. Only register listener once */
if (xmppConnectionListener == null) {
xmppConnectionListener = new XMPPConnectionListener();
mConnection.addConnectionListener(xmppConnectionListener);
}
// Allow longer timeout during login for slow client device; clear to default in caller
mConnection.setReplyTimeout(SMACK_REPLY_EXTENDED_TIMEOUT_30);
// Init the connection SynchronizedPoints
xmppConnected = new LoginSynchronizationPoint<>(this, "connection connected");
Timber.i("Starting XMPP Connection...: %s", mInetSocketAddress);
try {
mConnection.connect();
} catch (StreamErrorException ex) {
String errMsg = ex.getMessage();
if (StringUtils.isEmpty(errMsg))
errMsg = ex.getStreamError().getDescriptiveText();
Timber.e("Encounter problem during XMPPConnection: %s", errMsg);
StanzaError stanzaError = StanzaError.from(Condition.policy_violation, errMsg).build();
throw new XMPPErrorException(null, stanzaError);
// } catch (DnssecValidationFailedException | IllegalArgumentException ex) {
} catch (DnssecValidationFailedException ex) {
String errMsg = ex.getMessage();
StanzaError stanzaError = StanzaError.from(Condition.not_authorized, errMsg).build();
throw new XMPPErrorException(null, stanzaError);
} catch (SecurityRequiredByServerException ex) {
// "SSL/TLS required by server but disabled in client"
String errMsg = ex.getMessage();
StanzaError stanzaError = StanzaError.from(Condition.not_allowed, errMsg).build();
throw new XMPPErrorException(null, stanzaError);
} catch (SecurityRequiredByClientException ex) {
// "SSL/TLS required by client but not supported by server"
String errMsg = ex.getMessage();
StanzaError stanzaError = StanzaError.from(Condition.service_unavailable, errMsg).build();
throw new XMPPErrorException(null, stanzaError);
} catch (XMPPException | SmackException | IOException | InterruptedException | NullPointerException ex) {
// if (ex.getCause() instanceof SSLHandshakeException) {
// Timber.e(ex.getCause());
// }
String errMsg = aTalkApp.getResString(R.string.service_gui_XMPP_EXCEPTION, ex.getMessage());
Timber.e("%s", errMsg);
StanzaError stanzaError = StanzaError.from(Condition.remote_server_timeout, errMsg).build();
throw new XMPPErrorException(null, stanzaError);
}
try {
/*
* Wait for connectionListener to report connection status. Exception handled in the above try/catch
*/
Timber.d("Entering check IfSuccess Or Wait or Throw!");
xmppConnected.checkIfSuccessOrWaitOrThrow();
} catch (InterruptedException e) {
e.printStackTrace();
}
// Check if user has cancelled the Trusted Certificate confirmation request
if (abortConnecting) {
abortConnecting = false;
disconnectAndCleanConnection();
return ConnectState.ABORT_CONNECTING;
}
if (!mConnection.isConnected()) {
Timber.e("XMPPConnection establishment has failed!");
// mConnection is not connected, lets set the mConnection state as failed;
disconnectAndCleanConnection();
eventDuringLogin = null;
fireRegistrationStateChanged(getRegistrationState(),
RegistrationState.CONNECTION_FAILED, RegistrationStateChangeEvent.REASON_SERVER_NOT_FOUND, null);
return ConnectState.ABORT_CONNECTING;
}
// cmeng - leave the registering state broadcast when xmpp is connected - may be better to do it here
fireRegistrationStateChanged(RegistrationState.UNREGISTERED, RegistrationState.REGISTERING,
RegistrationStateChangeEvent.REASON_NOT_SPECIFIED, null);
// Init the user authentication SynchronizedPoints
accountAuthenticated = new LoginSynchronizationPoint<>(this, "account authenticated");
boolean success = false;
try {
success = loginStrategy.login(mConnection, userName, mResource);
} catch (StreamErrorException ex) {
String errMsg = ex.getStreamError().getDescriptiveText();
Timber.e("Encounter problem during XMPPConnection: %s", errMsg);
StanzaError stanzaError = StanzaError.from(Condition.policy_violation, errMsg).build();
throw new XMPPErrorException(null, stanzaError);
} catch (SmackException | XMPPException | InterruptedException | IOException el) {
String errMsg = el.getMessage();
/*
* If account is not registered on server, send IB registration request to server if user
* enable the option. Otherwise throw back to user and ask for InBand registration confirmation.
*/
if (StringUtils.isNotEmpty(errMsg) && errMsg.contains("not-authorized")) {
if (mAccountID.isIbRegistration()) {
try {
// Server sends stream disconnect on "not-authorized". So perform manual connect again before
// server closes the stream. Some Server does otherwise, so check before making connection.
if (!mConnection.isConnected())
mConnection.connect();
// stop pps connectionListener from disturbing IBR registration process
mConnection.removeConnectionListener(xmppConnectionListener);
xmppConnectionListener = null;
accountIBRegistered = new LoginSynchronizationPoint<>(this, "account ib registered");
loginStrategy.registerAccount(this, mAccountID);
eventDuringLogin = null;
return ConnectState.STOP_TRYING;
} catch (StreamErrorException ex) {
errMsg = ex.getStreamError().getDescriptiveText();
Timber.e("Encounter problem during XMPPConnection: %s", errMsg);
StanzaError stanzaError = StanzaError.from(Condition.policy_violation, errMsg).build();
throw new XMPPErrorException(null, stanzaError);
} catch (SmackException | XMPPException | InterruptedException | IOException | NullPointerException err) {
disconnectAndCleanConnection();
eventDuringLogin = null;
fireRegistrationStateChanged(getRegistrationState(), RegistrationState.CONNECTION_FAILED,
RegistrationStateChangeEvent.REASON_IB_REGISTRATION_FAILED,
loginStrategy.getClass().getName() + " requests abort");
errMsg = err.getMessage();
if (StringUtils.isNotEmpty(errMsg) && !errMsg.contains("registration-required")) {
errMsg = aTalkApp.getResString(R.string.service_gui_REGISTRATION_REQUIRED, errMsg);
Timber.e("%s", errMsg);
StanzaError stanzaError = StanzaError.from(Condition.forbidden, errMsg).build();
throw new XMPPErrorException(null, stanzaError);
}
else {
Timber.e("%s", errMsg);
StanzaError stanzaError = StanzaError.from(Condition.registration_required, errMsg).build();
throw new XMPPErrorException(null, stanzaError);
}
}
}
else {
if (el instanceof SASLErrorException) {
errMsg += ": " + ((SASLErrorException) el).getSASLFailure().getDescriptiveText();
}
errMsg = aTalkApp.getResString(R.string.service_gui_NOT_AUTHORIZED_HINT, errMsg);
StanzaError stanzaError = StanzaError.from(Condition.not_authorized, errMsg).build();
throw new XMPPErrorException(null, stanzaError);
}
}
}
// cmeng - sometimes exception and crash after this point during apk debug launch. android JIT problem
try {
// wait for connectionListener to report status. Exceptions are handled in try/catch
accountAuthenticated.checkIfSuccessOrWait();
} catch (InterruptedException e) {
Timber.w("Xmpp Connection authentication exception: %s", e.getMessage());
}
if (!success) {
disconnectAndCleanConnection();
eventDuringLogin = null;
fireRegistrationStateChanged(getRegistrationState(),
RegistrationState.CONNECTION_FAILED, RegistrationStateChangeEvent.REASON_AUTHENTICATION_FAILED,
loginStrategy.getClass().getName() + " requests abort");
return ConnectState.ABORT_CONNECTING;
}
if (mConnection.isAuthenticated()) {
return ConnectState.STOP_TRYING;
}
else {
disconnectAndCleanConnection();
eventDuringLogin = null;
fireRegistrationStateChanged(getRegistrationState(), RegistrationState.UNREGISTERED,
RegistrationStateChangeEvent.REASON_NOT_SPECIFIED, null);
return ConnectState.CONTINUE_TRYING;
}
}