From 9c890032c042ffc4db17dc9b64e88875cbd29d83 Mon Sep 17 00:00:00 2001 From: Eric House Date: Wed, 10 Jun 2020 08:31:55 -0700 Subject: [PATCH] implement relay backoff timer Moving logic into the timer itself. There's always meant to be one running, set from between 10 seconds and 23 hours from now. Code receiving messages (mqtt or relay) resets the backoff when a message is received, so when there's activity the timer should stay short. Somebody with no games at all will have attempts made to connect to the relay and mosquitto once/day, which is when invitations via that method would be received. Devices with FCM should see lower latency of course. --- .../eehouse/android/xw4/BoardDelegate.java | 2 +- .../android/xw4/ConnStatusHandler.java | 2 +- .../android/xw4/ConnViaViewLayout.java | 2 +- .../java/org/eehouse/android/xw4/DBUtils.java | 4 - .../org/eehouse/android/xw4/DlgDelegate.java | 1 + .../org/eehouse/android/xw4/MQTTUtils.java | 26 +++++++ .../eehouse/android/xw4/OnBootReceiver.java | 2 +- .../android/xw4/PollListPreference.java | 67 ----------------- .../org/eehouse/android/xw4/RelayService.java | 29 ++------ .../android/xw4/RelayTimerReceiver.java | 73 +++++++++++++------ .../java/org/eehouse/android/xw4/XWPrefs.java | 10 ++- .../app/src/main/res/values/strings.xml | 8 +- 12 files changed, 101 insertions(+), 125 deletions(-) delete mode 100644 xwords4/android/app/src/main/java/org/eehouse/android/xw4/PollListPreference.java diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java index 73583189f..b6a5310e0 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java @@ -2745,7 +2745,7 @@ public class BoardDelegate extends DelegateBase } } if ( m_connTypes.contains( CommsConnType.COMMS_CONN_RELAY ) ) { - if ( !RelayService.relayEnabled( m_activity ) ) { + if ( !XWPrefs.getRelayEnabled( m_activity ) ) { m_dropRelayOnDismiss = false; String msg = getString( R.string.warn_relay_disabled ) + "\n\n" + getString( R.string.warn_relay_remove ); diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/ConnStatusHandler.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/ConnStatusHandler.java index 2912096b0..0d4d7993c 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/ConnStatusHandler.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/ConnStatusHandler.java @@ -680,7 +680,7 @@ public class ConnStatusHandler { //!getAirplaneModeOn( context ); break; case COMMS_CONN_RELAY: - result = RelayService.relayEnabled( context ) + result = XWPrefs.getRelayEnabled( context ) && NetStateCache.netAvail( context ); break; case COMMS_CONN_P2P: diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/ConnViaViewLayout.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/ConnViaViewLayout.java index bea4e8fea..2a0bca05c 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/ConnViaViewLayout.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/ConnViaViewLayout.java @@ -125,7 +125,7 @@ public class ConnViaViewLayout extends LinearLayout { enabled = BTService.BTEnabled(); break; case COMMS_CONN_RELAY: - enabled = RelayService.relayEnabled( context ); + enabled = XWPrefs.getRelayEnabled( context ); break; case COMMS_CONN_P2P: enabled = WiDirWrapper.enabled(); diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DBUtils.java index d29cce2b3..da5b5cacc 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DBUtils.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DBUtils.java @@ -370,10 +370,6 @@ public class DBUtils { if ( null != summary ) { // nag time may have changed NagTurnReceiver.setNagTimer( context ); } - - if ( needsTimer ) { - RelayTimerReceiver.setTimer( context ); - } } // saveSummary public static void addRematchInfo( Context context, long rowid, String btAddr, diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DlgDelegate.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DlgDelegate.java index 8fc7267ac..9877ab87c 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DlgDelegate.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DlgDelegate.java @@ -433,6 +433,7 @@ public class DlgDelegate { makeOkOnlyBuilder( R.string.no_games_to_refresh ).show(); } else { RelayService.timerFired( m_activity ); + MQTTUtils.timerFired( m_activity ); Utils.showToast( m_activity, R.string.msgs_progress ); } } diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/MQTTUtils.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/MQTTUtils.java index 7612af656..34ff8e7fa 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/MQTTUtils.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/MQTTUtils.java @@ -82,6 +82,19 @@ public class MQTTUtils extends Thread implements IMqttActionListener, MqttCallba getOrStart( context ); } + public static void timerFired( Context context ) + { + MQTTUtils instance; + synchronized ( sInstance ) { + instance = sInstance[0]; + } + + if ( null != instance && !instance.isConnected() ) { + clearInstance( instance ); + } + getOrStart( context ); // no-op if have instance + } + static void onConfigChanged( Context context ) { MQTTUtils instance; @@ -160,6 +173,16 @@ public class MQTTUtils extends Thread implements IMqttActionListener, MqttCallba now - startTime ); } + private boolean isConnected() + { + MqttAsyncClient client = mClient; + boolean result = null != client + && client.isConnected() + && mState != State.CLOSING; + Log.d( TAG, "isConnected() => %b", result ); + return result; + } + private void enqueue( String topic, byte[] packet ) { mOutboundQueue.add( new MessagePair( topic, packet ) ); @@ -435,6 +458,8 @@ public class MQTTUtils extends Thread implements IMqttActionListener, MqttCallba mMsgThread.add( message.getPayload() ); ConnStatusHandler .updateStatusIn( mContext, CommsConnType.COMMS_CONN_MQTT, true ); + + RelayTimerReceiver.restartBackoff( mContext, TAG ); } @Override @@ -443,6 +468,7 @@ public class MQTTUtils extends Thread implements IMqttActionListener, MqttCallba Log.d( TAG, "%H.deliveryComplete(token=%s)", this, token ); ConnStatusHandler .updateStatusOut( mContext, CommsConnType.COMMS_CONN_MQTT, true ); + RelayTimerReceiver.restartBackoff( mContext, TAG ); } private void subscribe() diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/OnBootReceiver.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/OnBootReceiver.java index dcff3fe47..16152b68a 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/OnBootReceiver.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/OnBootReceiver.java @@ -45,7 +45,7 @@ public class OnBootReceiver extends BroadcastReceiver { protected static void startTimers( Context context ) { NagTurnReceiver.restartTimer( context ); - RelayTimerReceiver.setTimer( context ); + RelayTimerReceiver.setTimer( context, true ); SMSResendReceiver.setTimer( context ); } } diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/PollListPreference.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/PollListPreference.java deleted file mode 100644 index 2c69c7514..000000000 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/PollListPreference.java +++ /dev/null @@ -1,67 +0,0 @@ -/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */ -/* - * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All - * rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -package org.eehouse.android.xw4; - -import android.content.Context; -import android.preference.ListPreference; -import android.preference.Preference; -import android.util.AttributeSet; - - -public class PollListPreference extends ListPreference - implements Preference.OnPreferenceChangeListener { - - private Context m_context; - - public PollListPreference( Context context, AttributeSet attrs ) - { - super( context, attrs ); - m_context = context; - setOnPreferenceChangeListener( this ); - } - - @Override - protected void onAttachedToActivity() - { - String val = getPersistedString( "0" ); - setSummaryToMatch( val ); - } - - // Preference.OnPreferenceChangeListener interface - public boolean onPreferenceChange( Preference preference, Object newValue ) - { - String valstr = (String)newValue; - int val = Integer.parseInt(valstr); - RelayTimerReceiver.setTimer( m_context, val * 1000 ); - - setSummaryToMatch( valstr ); - return true; - } - - private void setSummaryToMatch( String value ) - { - int index = findIndexOfValue( value ); - if ( 0 <= index ) { - CharSequence entry = getEntries()[index]; - setSummary( entry ); - } - } -} diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/RelayService.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/RelayService.java index 5e47cc29f..124fc5615 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/RelayService.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/RelayService.java @@ -192,16 +192,8 @@ public class RelayService extends XWJIService return s_lastFCM; } - public static boolean relayEnabled( Context context ) - { - boolean enabled = ! XWPrefs - .getPrefsBoolean( context, R.string.key_disable_relay, false ); - // Log.d( TAG, "relayEnabled() => %b", enabled ); - return enabled; - } - public static void enabledChanged( Context context ) { - boolean enabled = relayEnabled( context ); + boolean enabled = XWPrefs.getRelayEnabled( context ); if ( enabled ) { startService( context ); } else { @@ -421,13 +413,6 @@ public class RelayService extends XWJIService } } - if ( shouldMaintainConnection() ) { - long interval_millis = getMaxIntervalSeconds() * 1000; - RelayTimerReceiver.setTimer( this, interval_millis ); - // Log.d( TAG, "onDestroy(): rescheduling in %d ms", - // interval_millis ); - } - super.onDestroy(); // Log.d( TAG, "%s.onDestroy() DONE", this ); } @@ -517,7 +502,6 @@ public class RelayService extends XWJIService } else if ( registerWithRelayIfNot( timestamp ) ) { requestMessages( timestamp ); } - RelayTimerReceiver.setTimer( this ); break; case STOP: stopThreads(); @@ -781,7 +765,7 @@ public class RelayService extends XWJIService private boolean startFetchThreadIfNotUDP() { // DbgUtils.logf( "startFetchThreadIfNotUDP()" ); - boolean handled = relayEnabled( this ) && !BuildConfig.UDP_ENABLED; + boolean handled = XWPrefs.getRelayEnabled( this ) && !BuildConfig.UDP_ENABLED; if ( handled && null == m_fetchThread ) { Assert.failDbg(); // NOT using this now! @@ -814,7 +798,7 @@ public class RelayService extends XWJIService private UDPReadThread startUDPReadThreadOnce() { UDPReadThread thread = null; - if ( BuildConfig.UDP_ENABLED && relayEnabled( this ) ) { + if ( BuildConfig.UDP_ENABLED && XWPrefs.getRelayEnabled( this ) ) { synchronized ( sUDPReadThreadRef ) { thread = sUDPReadThreadRef.get(); if ( null == thread ) { @@ -997,6 +981,7 @@ public class RelayService extends XWJIService private void gotPacket( DatagramPacket packet ) { ConnStatusHandler.showSuccessIn(); + RelayTimerReceiver.restartBackoff( this, TAG ); int packetLen = packet.getLength(); byte[] data = new byte[packetLen]; @@ -1007,7 +992,7 @@ public class RelayService extends XWJIService private boolean shouldRegister() { - boolean should = relayEnabled( this ); + boolean should = XWPrefs.getRelayEnabled( this ); if ( should ) { String relayID = DevID.getRelayDevID( this, true ); boolean registered = null != relayID; @@ -1588,7 +1573,7 @@ public class RelayService extends XWJIService private void startThreads() { Log.d( TAG, "startThreads()" ); - if ( !relayEnabled( this ) || !NetStateCache.netAvail( this ) ) { + if ( !XWPrefs.getRelayEnabled( this ) || !NetStateCache.netAvail( this ) ) { stopThreads(); } else if ( BuildConfig.UDP_ENABLED ) { stopFetchThreadIf(); @@ -1720,7 +1705,7 @@ public class RelayService extends XWJIService private boolean shouldMaintainConnection() { - boolean result = relayEnabled( this ) + boolean result = XWPrefs.getRelayEnabled( this ) && (0 == s_lastFCM || XWPrefs.getIgnoreFCM( this )); if ( result ) { diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/RelayTimerReceiver.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/RelayTimerReceiver.java index 60235b656..efa4735e8 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/RelayTimerReceiver.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/RelayTimerReceiver.java @@ -29,36 +29,65 @@ import android.os.SystemClock; public class RelayTimerReceiver extends BroadcastReceiver { private static final String TAG = RelayTimerReceiver.class.getSimpleName(); + private static final String KEY_BACKOFF = TAG + "/backoff"; + private static final String KEY_NEXT_BACKOFF = TAG + "/next_backoff"; + private static final long MIN_BACKOFF = 1000 * 10; // 10 seconds + private static final long MAX_BACKOFF = 1000 * 60 * 60 * 32; // 23 hours @Override public void onReceive( Context context, Intent intent ) { Log.d( TAG, "onReceive(intent=%s)", intent ); RelayService.timerFired( context ); - } + MQTTUtils.timerFired( context ); - public static void setTimer( Context context ) - { - setTimer( context, 1000 * 1800 ); // to be changed shortly - } - - public static void setTimer( Context context, long interval_millis ) - { - AlarmManager am = - (AlarmManager)context.getSystemService( Context.ALARM_SERVICE ); - - Intent intent = new Intent( context, RelayTimerReceiver.class ); - PendingIntent pi = PendingIntent.getBroadcast( context, 0, intent, 0 ); - - // Check if we have any relay IDs, since we'll be using them to - // identify connected games for which we can fetch messages - if ( interval_millis > 0 && DBUtils.haveRelayIDs( context ) ) { - long fire_millis = SystemClock.elapsedRealtime() + interval_millis; - am.set( AlarmManager.ELAPSED_REALTIME_WAKEUP, fire_millis, pi ); + long nextBackoff = DBUtils.getLongFor( context, KEY_BACKOFF, MIN_BACKOFF ); + if ( nextBackoff == MAX_BACKOFF ) { + // at max, so no change and nothing to save } else { - // will happen if user's set getProxyIntervalSeconds to return 0 - am.cancel( pi ); + nextBackoff *= 2; + if ( nextBackoff > MAX_BACKOFF ) { + nextBackoff = MAX_BACKOFF; + } + DBUtils.setLongFor( context, KEY_BACKOFF, nextBackoff ); + } + setTimer( context, nextBackoff, true ); + } + + static void restartBackoff( Context context, String tag ) + { + DBUtils.setLongFor( context, KEY_BACKOFF, MIN_BACKOFF ); + setTimer( context, MIN_BACKOFF, false ); + } + + static void setTimer( Context context, boolean force ) + { + long backoff = DBUtils.getLongFor( context, KEY_BACKOFF, MIN_BACKOFF ); + setTimer( context, backoff, force ); + } + + private synchronized static void setTimer( Context context, long backoff, boolean force ) + { + if ( XWPrefs.getRelayEnabled( context ) ) { + if ( !force ) { + long curBackoff = DBUtils.getLongFor( context, KEY_NEXT_BACKOFF, MIN_BACKOFF ); + force = backoff != curBackoff; + } + if ( force ) { + long now = SystemClock.elapsedRealtime(); + long fireMillis = now + backoff; + + AlarmManager am = + (AlarmManager)context.getSystemService( Context.ALARM_SERVICE ); + + Intent intent = new Intent( context, RelayTimerReceiver.class ); + PendingIntent pi = PendingIntent.getBroadcast( context, 0, intent, 0 ); + am.set( AlarmManager.ELAPSED_REALTIME_WAKEUP, fireMillis, pi ); + Log.d( TAG, "setTimer() set for %d seconds from now (%d)", backoff / 1000, now / 1000 ); + DBUtils.setLongFor( context, KEY_NEXT_BACKOFF, backoff ); + } + } else { + Log.d( TAG, "setTimer(): relay disabled, so dropping" ); } } - } diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/XWPrefs.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/XWPrefs.java index 165e9f1ea..76db23fab 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/XWPrefs.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/XWPrefs.java @@ -148,6 +148,14 @@ public class XWPrefs { return result; } + public static boolean getRelayEnabled( Context context ) + { + boolean enabled = ! getPrefsBoolean( context, R.string.key_disable_relay, + false ); + // Log.d( TAG, "getRelayEnabled() => %b", enabled ); + return enabled; + } + public static boolean getSkipToWebAPI( Context context ) { return getPrefsBoolean( context, R.string.key_relay_via_http_first, false ); @@ -518,7 +526,7 @@ public class XWPrefs { int flags = getPrefsInt( context, R.string.key_addrs_pref, -1 ); if ( -1 == flags ) { result = new CommsConnTypeSet(); - if ( RelayService.relayEnabled( context ) ) { + if ( getRelayEnabled( context ) ) { result.add( CommsConnType.COMMS_CONN_RELAY ); } if ( BuildConfig.OFFER_MQTT ) { diff --git a/xwords4/android/app/src/main/res/values/strings.xml b/xwords4/android/app/src/main/res/values/strings.xml index bdb8946bc..f51e491b6 100644 --- a/xwords4/android/app/src/main/res/values/strings.xml +++ b/xwords4/android/app/src/main/res/values/strings.xml @@ -1334,12 +1334,10 @@ - + This action checks the relay for - pending moves/messages for all networked games and flags those - with pending moves. When you open a flagged game it will connect - and sync. (In a later release these moves will be downloaded in - the background.) + pending moves/messages for all networked games. You are entering tile-exchange mode.\n\nTap tiles to add/remove them from the set to be