synchronzie on xmpp service around all state changes

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java | 219 
1 file changed, 113 insertions(+), 106 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -298,7 +298,7 @@ public class XmppConnectionService extends Service {
 				mOnAccountUpdate.onAccountUpdate();
 			}
 			if (account.getStatus() == Account.State.ONLINE) {
-				synchronized (mLowPingTimeoutMode) {
+				synchronized (XmppConnectionService.this) {
 					if (mLowPingTimeoutMode.remove(account.getJid().toBareJid())) {
 						Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": leaving low ping timeout mode");
 					}
@@ -335,33 +335,35 @@ public class XmppConnectionService extends Service {
 				}
 				account.pendingConferenceJoins.clear();
 				scheduleWakeUpCall(Config.PING_MAX_INTERVAL, account.getUuid().hashCode());
-			} else if (account.getStatus() == Account.State.OFFLINE || account.getStatus() == Account.State.DISABLED) {
-				resetSendingToWaiting(account);
-				if (!account.isOptionSet(Account.OPTION_DISABLED)) {
-					synchronized (mLowPingTimeoutMode) {
-						if (mLowPingTimeoutMode.contains(account.getJid().toBareJid())) {
-							Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": went into offline state during low ping mode. reconnecting now");
-							reconnectAccount(account, true, false);
-						} else {
-							int timeToReconnect = mRandom.nextInt(20) + 10;
-							scheduleWakeUpCall(timeToReconnect, account.getUuid().hashCode());
+			} else {
+				synchronized (XmppConnectionService.this) {
+					if (account.getStatus() == Account.State.OFFLINE || account.getStatus() == Account.State.DISABLED) {
+						resetSendingToWaiting(account);
+						if (!account.isOptionSet(Account.OPTION_DISABLED)) {
+							if (mLowPingTimeoutMode.contains(account.getJid().toBareJid())) {
+								Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": went into offline state during low ping mode. reconnecting now");
+								reconnectAccount(account, true, false);
+							} else {
+								int timeToReconnect = mRandom.nextInt(20) + 10;
+								scheduleWakeUpCall(timeToReconnect, account.getUuid().hashCode());
+							}
+						}
+					} else if (account.getStatus() == Account.State.REGISTRATION_SUCCESSFUL) {
+						databaseBackend.updateAccount(account);
+						reconnectAccount(account, true, false);
+					} else if ((account.getStatus() != Account.State.CONNECTING)
+							&& (account.getStatus() != Account.State.NO_INTERNET)) {
+						resetSendingToWaiting(account);
+						if (connection != null) {
+							int next = connection.getTimeToNextAttempt();
+							Log.d(Config.LOGTAG, account.getJid().toBareJid()
+									+ ": error connecting account. try again in "
+									+ next + "s for the "
+									+ (connection.getAttempt() + 1) + " time");
+							scheduleWakeUpCall(next, account.getUuid().hashCode());
 						}
 					}
 				}
-			} else if (account.getStatus() == Account.State.REGISTRATION_SUCCESSFUL) {
-				databaseBackend.updateAccount(account);
-				reconnectAccount(account, true, false);
-			} else if ((account.getStatus() != Account.State.CONNECTING)
-					&& (account.getStatus() != Account.State.NO_INTERNET)) {
-				resetSendingToWaiting(account);
-				if (connection != null) {
-					int next = connection.getTimeToNextAttempt();
-					Log.d(Config.LOGTAG, account.getJid().toBareJid()
-							+ ": error connecting account. try again in "
-							+ next + "s for the "
-							+ (connection.getAttempt() + 1) + " time");
-					scheduleWakeUpCall(next, account.getUuid().hashCode());
-				}
 			}
 			getNotificationService().updateErrorNotification();
 		}
@@ -611,103 +613,108 @@ public class XmppConnectionService extends Service {
 					break;
 			}
 		}
-		this.wakeLock.acquire();
+		synchronized (this) {
+			this.wakeLock.acquire();
+			boolean pingNow = false;
+			HashSet<Account> pingCandidates = new HashSet<>();
+			for (Account account : accounts) {
+				pingNow |= processAccountState(account,
+						interactive,
+						"ui".equals(action),
+						CryptoHelper.getAccountFingerprint(account).equals(pushedAccountHash),
+						pingCandidates);
+			}
+			if (pingNow) {
+				for (Account account : pingCandidates) {
+					final boolean lowTimeout = mLowPingTimeoutMode.contains(account.getJid().toBareJid());
+					account.getXmppConnection().sendPing();
+					Log.d(Config.LOGTAG, account.getJid().toBareJid() + " send ping (action=" + action + ",lowTimeout=" + Boolean.toString(lowTimeout) + ")");
+					scheduleWakeUpCall(lowTimeout ? Config.LOW_PING_TIMEOUT : Config.PING_TIMEOUT, account.getUuid().hashCode());
+				}
+			}
+			if (wakeLock.isHeld()) {
+				try {
+					wakeLock.release();
+				} catch (final RuntimeException ignored) {
+				}
+			}
+		}
+		return START_STICKY;
+	}
 
+	private boolean processAccountState(Account account, boolean interactive, boolean isUiAction, boolean isAccountPushed, HashSet<Account> pingCandidates) {
 		boolean pingNow = false;
-		HashSet<Account> pingCandidates = new HashSet<>();
-
-		for (Account account : accounts) {
-			if (!account.isOptionSet(Account.OPTION_DISABLED)) {
-				if (!hasInternetConnection()) {
-					account.setStatus(Account.State.NO_INTERNET);
+		if (!account.isOptionSet(Account.OPTION_DISABLED)) {
+			if (!hasInternetConnection()) {
+				account.setStatus(Account.State.NO_INTERNET);
+				if (statusListener != null) {
+					statusListener.onStatusChanged(account);
+				}
+			} else {
+				if (account.getStatus() == Account.State.NO_INTERNET) {
+					account.setStatus(Account.State.OFFLINE);
 					if (statusListener != null) {
 						statusListener.onStatusChanged(account);
 					}
-				} else {
-					if (account.getStatus() == Account.State.NO_INTERNET) {
-						account.setStatus(Account.State.OFFLINE);
-						if (statusListener != null) {
-							statusListener.onStatusChanged(account);
-						}
-					}
-					if (account.getStatus() == Account.State.ONLINE) {
-						synchronized (mLowPingTimeoutMode) {
-							long lastReceived = account.getXmppConnection().getLastPacketReceived();
-							long lastSent = account.getXmppConnection().getLastPingSent();
-							long pingInterval = "ui".equals(action) ? Config.PING_MIN_INTERVAL * 1000 : Config.PING_MAX_INTERVAL * 1000;
-							long msToNextPing = (Math.max(lastReceived, lastSent) + pingInterval) - SystemClock.elapsedRealtime();
-							int pingTimeout = mLowPingTimeoutMode.contains(account.getJid().toBareJid()) ? Config.LOW_PING_TIMEOUT * 1000 : Config.PING_TIMEOUT * 1000;
-							long pingTimeoutIn = (lastSent + pingTimeout) - SystemClock.elapsedRealtime();
-							if (lastSent > lastReceived) {
-								if (pingTimeoutIn < 0) {
-									Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": ping timeout");
-									this.reconnectAccount(account, true, interactive);
-								} else {
-									int secs = (int) (pingTimeoutIn / 1000);
-									this.scheduleWakeUpCall(secs, account.getUuid().hashCode());
+				}
+				if (account.getStatus() == Account.State.ONLINE) {
+					synchronized (mLowPingTimeoutMode) {
+						long lastReceived = account.getXmppConnection().getLastPacketReceived();
+						long lastSent = account.getXmppConnection().getLastPingSent();
+						long pingInterval = isUiAction ? Config.PING_MIN_INTERVAL * 1000 : Config.PING_MAX_INTERVAL * 1000;
+						long msToNextPing = (Math.max(lastReceived, lastSent) + pingInterval) - SystemClock.elapsedRealtime();
+						int pingTimeout = mLowPingTimeoutMode.contains(account.getJid().toBareJid()) ? Config.LOW_PING_TIMEOUT * 1000 : Config.PING_TIMEOUT * 1000;
+						long pingTimeoutIn = (lastSent + pingTimeout) - SystemClock.elapsedRealtime();
+						if (lastSent > lastReceived) {
+							if (pingTimeoutIn < 0) {
+								Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": ping timeout");
+								this.reconnectAccount(account, true, interactive);
+							} else {
+								int secs = (int) (pingTimeoutIn / 1000);
+								this.scheduleWakeUpCall(secs, account.getUuid().hashCode());
+							}
+						} else {
+							pingCandidates.add(account);
+							if (isAccountPushed) {
+								pingNow = true;
+								if (mLowPingTimeoutMode.add(account.getJid().toBareJid())) {
+									Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": entering low ping timeout mode");
 								}
+							} else if (msToNextPing <= 0) {
+								pingNow = true;
 							} else {
-								pingCandidates.add(account);
-								if (CryptoHelper.getAccountFingerprint(account).equals(pushedAccountHash)) {
-									pingNow = true;
-									if (mLowPingTimeoutMode.add(account.getJid().toBareJid())) {
-										Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": entering low ping timeout mode");
-									}
-								} else if (msToNextPing <= 0) {
-									pingNow = true;
-								} else {
-									this.scheduleWakeUpCall((int) (msToNextPing / 1000), account.getUuid().hashCode());
-									if (mLowPingTimeoutMode.remove(account.getJid().toBareJid())) {
-										Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": leaving low ping timeout mode");
-									}
+								this.scheduleWakeUpCall((int) (msToNextPing / 1000), account.getUuid().hashCode());
+								if (mLowPingTimeoutMode.remove(account.getJid().toBareJid())) {
+									Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": leaving low ping timeout mode");
 								}
 							}
 						}
-					} else if (account.getStatus() == Account.State.OFFLINE) {
+					}
+				} else if (account.getStatus() == Account.State.OFFLINE) {
+					reconnectAccount(account, true, interactive);
+				} else if (account.getStatus() == Account.State.CONNECTING) {
+					long secondsSinceLastConnect = (SystemClock.elapsedRealtime() - account.getXmppConnection().getLastConnect()) / 1000;
+					long secondsSinceLastDisco = (SystemClock.elapsedRealtime() - account.getXmppConnection().getLastDiscoStarted()) / 1000;
+					long discoTimeout = Config.CONNECT_DISCO_TIMEOUT - secondsSinceLastDisco;
+					long timeout = Config.CONNECT_TIMEOUT - secondsSinceLastConnect;
+					if (timeout < 0) {
+						Log.d(Config.LOGTAG, account.getJid() + ": time out during connect reconnecting");
+						account.getXmppConnection().resetAttemptCount(false);
 						reconnectAccount(account, true, interactive);
-					} else if (account.getStatus() == Account.State.CONNECTING) {
-						long secondsSinceLastConnect = (SystemClock.elapsedRealtime() - account.getXmppConnection().getLastConnect()) / 1000;
-						long secondsSinceLastDisco = (SystemClock.elapsedRealtime() - account.getXmppConnection().getLastDiscoStarted()) / 1000;
-						long discoTimeout = Config.CONNECT_DISCO_TIMEOUT - secondsSinceLastDisco;
-						long timeout = Config.CONNECT_TIMEOUT - secondsSinceLastConnect;
-						if (timeout < 0) {
-							Log.d(Config.LOGTAG, account.getJid() + ": time out during connect reconnecting");
-							account.getXmppConnection().resetAttemptCount(false);
-							reconnectAccount(account, true, interactive);
-						} else if (discoTimeout < 0) {
-							account.getXmppConnection().sendDiscoTimeout();
-							scheduleWakeUpCall((int) Math.min(timeout,discoTimeout), account.getUuid().hashCode());
-						} else {
-							scheduleWakeUpCall((int) Math.min(timeout,discoTimeout), account.getUuid().hashCode());
-						}
+					} else if (discoTimeout < 0) {
+						account.getXmppConnection().sendDiscoTimeout();
+						scheduleWakeUpCall((int) Math.min(timeout,discoTimeout), account.getUuid().hashCode());
 					} else {
-						if (account.getXmppConnection().getTimeToNextAttempt() <= 0) {
-							reconnectAccount(account, true, interactive);
-						}
+						scheduleWakeUpCall((int) Math.min(timeout,discoTimeout), account.getUuid().hashCode());
+					}
+				} else {
+					if (account.getXmppConnection().getTimeToNextAttempt() <= 0) {
+						reconnectAccount(account, true, interactive);
 					}
-				}
-				if (mOnAccountUpdate != null) {
-					mOnAccountUpdate.onAccountUpdate();
-				}
-			}
-		}
-		if (pingNow) {
-			for (Account account : pingCandidates) {
-				synchronized (mLowPingTimeoutMode) {
-					final boolean lowTimeout = mLowPingTimeoutMode.contains(account.getJid().toBareJid());
-					account.getXmppConnection().sendPing();
-					Log.d(Config.LOGTAG, account.getJid().toBareJid() + " send ping (action=" + action + ",lowTimeout=" + Boolean.toString(lowTimeout) + ")");
-					scheduleWakeUpCall(lowTimeout ? Config.LOW_PING_TIMEOUT : Config.PING_TIMEOUT, account.getUuid().hashCode());
 				}
 			}
 		}
-		if (wakeLock.isHeld()) {
-			try {
-				wakeLock.release();
-			} catch (final RuntimeException ignored) {
-			}
-		}
-		return START_STICKY;
+		return pingNow;
 	}
 
 	public boolean isDataSaverDisabled() {