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.
This commit is contained in:
Eric House 2020-06-10 08:31:55 -07:00
parent 63835105e4
commit 9c890032c0
12 changed files with 101 additions and 125 deletions

View file

@ -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 );

View file

@ -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:

View file

@ -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();

View file

@ -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,

View file

@ -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 );
}
}

View file

@ -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()

View file

@ -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 );
}
}

View file

@ -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 );
}
}
}

View file

@ -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 ) {

View file

@ -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 );
long nextBackoff = DBUtils.getLongFor( context, KEY_BACKOFF, MIN_BACKOFF );
if ( nextBackoff == MAX_BACKOFF ) {
// at max, so no change and nothing to save
} else {
nextBackoff *= 2;
if ( nextBackoff > MAX_BACKOFF ) {
nextBackoff = MAX_BACKOFF;
}
DBUtils.setLongFor( context, KEY_BACKOFF, nextBackoff );
}
setTimer( context, nextBackoff, true );
}
public static void setTimer( Context context )
static void restartBackoff( Context context, String tag )
{
setTimer( context, 1000 * 1800 ); // to be changed shortly
DBUtils.setLongFor( context, KEY_BACKOFF, MIN_BACKOFF );
setTimer( context, MIN_BACKOFF, false );
}
public static void setTimer( Context context, long interval_millis )
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 );
// 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 );
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 {
// will happen if user's set getProxyIntervalSeconds to return 0
am.cancel( pi );
Log.d( TAG, "setTimer(): relay disabled, so dropping" );
}
}
}

View file

@ -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 ) {

View file

@ -1334,12 +1334,10 @@
<!-- The following strings (all whose names start with
"not_again") appear in the New user info dialog.
-->
<!-- shown when user chooses the gamel_menu_checkmoves menu -->
<!-- shown when user chooses the gamel_menu_checkmoves ("check for
moves") menu -->
<string name="not_again_sync">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.)</string>
pending moves/messages for all networked games.</string>
<!-- Shown when the user chooses the "board_menu_trade" menu -->
<string name="not_again_trading">You are entering tile-exchange
mode.\n\nTap tiles to add/remove them from the set to be