diff --git a/android/src/org/purplei2p/i2pd/DaemonSingleton.java b/android/src/org/purplei2p/i2pd/DaemonSingleton.java index 64568f83..cba29a18 100644 --- a/android/src/org/purplei2p/i2pd/DaemonSingleton.java +++ b/android/src/org/purplei2p/i2pd/DaemonSingleton.java @@ -8,8 +8,8 @@ import android.util.Log; public class DaemonSingleton { private static final String TAG="i2pd"; private static final DaemonSingleton instance = new DaemonSingleton(); - public static interface StateUpdateListener { void daemonStateUpdate(); } - private final Set stateUpdateListeners = new HashSet(); + public interface StateUpdateListener { void daemonStateUpdate(); } + private final Set stateUpdateListeners = new HashSet<>(); public static DaemonSingleton getInstance() { return instance; @@ -18,63 +18,54 @@ public class DaemonSingleton { public synchronized void addStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.add(listener); } public synchronized void removeStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.remove(listener); } + private synchronized void setState(State newState) { + if(newState==null)throw new NullPointerException(); + State oldState = state; + if(oldState==null)throw new NullPointerException(); + if(oldState.equals(newState))return; + state=newState; + fireStateUpdate1(); + } public synchronized void stopAcceptingTunnels() { if(isStartedOkay()){ - state=State.gracefulShutdownInProgress; - fireStateUpdate(); + setState(State.gracefulShutdownInProgress); I2PD_JNI.stopAcceptingTunnels(); } } - public void onNetworkStateChange(boolean isConnected) { - I2PD_JNI.onNetworkStateChanged(isConnected); - } - - private boolean startedOkay; + private volatile boolean startedOkay; - public static enum State {uninitialized,starting,jniLibraryLoaded,startedOkay,startFailed,gracefulShutdownInProgress,stopped}; + public enum State {uninitialized,starting,jniLibraryLoaded,startedOkay,startFailed,gracefulShutdownInProgress,stopped}; - private State state = State.uninitialized; + private volatile State state = State.uninitialized; public State getState() { return state; } - public synchronized void start() { - if(state != State.uninitialized)return; - state = State.starting; - fireStateUpdate(); + { + setState(State.starting); new Thread(new Runnable(){ @Override public void run() { try { I2PD_JNI.loadLibraries(); - synchronized (DaemonSingleton.this) { - state = State.jniLibraryLoaded; - fireStateUpdate(); - } + setState(State.jniLibraryLoaded); } catch (Throwable tr) { lastThrowable=tr; - synchronized (DaemonSingleton.this) { - state = State.startFailed; - fireStateUpdate(); - } + setState(State.startFailed); return; } try { synchronized (DaemonSingleton.this) { daemonStartResult = I2PD_JNI.startDaemon(); if("ok".equals(daemonStartResult)){ - state=State.startedOkay; + setState(State.startedOkay); setStartedOkay(true); - }else state=State.startFailed; - fireStateUpdate(); + }else setState(State.startFailed); } } catch (Throwable tr) { lastThrowable=tr; - synchronized (DaemonSingleton.this) { - state = State.startFailed; - fireStateUpdate(); - } + setState(State.startFailed); return; } } @@ -84,7 +75,7 @@ public class DaemonSingleton { private Throwable lastThrowable; private String daemonStartResult="N/A"; - private synchronized void fireStateUpdate() { + private void fireStateUpdate1() { Log.i(TAG, "daemon state change: "+state); for(StateUpdateListener listener : stateUpdateListeners) { try { @@ -121,10 +112,7 @@ public class DaemonSingleton { if(isStartedOkay()){ try {I2PD_JNI.stopDaemon();}catch(Throwable tr){Log.e(TAG, "", tr);} setStartedOkay(false); - synchronized (DaemonSingleton.this) { - state = State.stopped; - fireStateUpdate(); - } + setState(State.stopped); } } } diff --git a/android/src/org/purplei2p/i2pd/ForegroundService.java b/android/src/org/purplei2p/i2pd/ForegroundService.java index 74761b07..07254439 100644 --- a/android/src/org/purplei2p/i2pd/ForegroundService.java +++ b/android/src/org/purplei2p/i2pd/ForegroundService.java @@ -34,15 +34,13 @@ public class ForegroundService extends Service { // Display a notification about us starting. We put an icon in the status bar. showNotification(); - daemon.start(); // Tell the user we started. - Toast.makeText(this, R.string.i2pd_service_started, Toast.LENGTH_SHORT).show(); +// Toast.makeText(this, R.string.i2pd_service_started, Toast.LENGTH_SHORT).show(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("ForegroundService", "Received start id " + startId + ": " + intent); - daemon.start(); return START_STICKY; } @@ -54,7 +52,7 @@ public class ForegroundService extends Service { stopForeground(true); // Tell the user we stopped. - Toast.makeText(this, R.string.i2pd_service_stopped, Toast.LENGTH_SHORT).show(); +// Toast.makeText(this, R.string.i2pd_service_stopped, Toast.LENGTH_SHORT).show(); } @Override @@ -92,6 +90,6 @@ public class ForegroundService extends Service { startForeground(NOTIFICATION, notification); } - private final DaemonSingleton daemon = DaemonSingleton.getInstance(); + private static final DaemonSingleton daemon = DaemonSingleton.getInstance(); } diff --git a/android/src/org/purplei2p/i2pd/I2PDActivity.java b/android/src/org/purplei2p/i2pd/I2PDActivity.java index 36e992b3..64316112 100755 --- a/android/src/org/purplei2p/i2pd/I2PDActivity.java +++ b/android/src/org/purplei2p/i2pd/I2PDActivity.java @@ -23,9 +23,9 @@ public class I2PDActivity extends Activity { private TextView textView; - private final DaemonSingleton daemon = DaemonSingleton.getInstance(); + private static final DaemonSingleton daemon = DaemonSingleton.getInstance(); - private DaemonSingleton.StateUpdateListener daemonStateUpdatedListener = + private final DaemonSingleton.StateUpdateListener daemonStateUpdatedListener = new DaemonSingleton.StateUpdateListener() { @Override @@ -58,7 +58,7 @@ public class I2PDActivity extends Activity { textView = new TextView(this); setContentView(textView); - DaemonSingleton.getInstance().addStateChangeListener(daemonStateUpdatedListener); + daemon.addStateChangeListener(daemonStateUpdatedListener); daemonStateUpdatedListener.daemonStateUpdate(); //set the app be foreground @@ -68,22 +68,18 @@ public class I2PDActivity extends Activity { @Override protected void onDestroy() { super.onDestroy(); - localDestroy(); - } - - private void localDestroy() { - textView = null; - DaemonSingleton.getInstance().removeStateChangeListener(daemonStateUpdatedListener); - Timer gracefulQuitTimer = getGracefulQuitTimer(); - if(gracefulQuitTimer!=null) { - gracefulQuitTimer.cancel(); - setGracefulQuitTimer(null); + textView = null; + daemon.removeStateChangeListener(daemonStateUpdatedListener); + Timer gracefulQuitTimer = getGracefulQuitTimer(); + if(gracefulQuitTimer!=null) { + gracefulQuitTimer.cancel(); + setGracefulQuitTimer(null); + } + try{ + doUnbindService(); + }catch(Throwable tr){ + Log.e(TAG, "", tr); } -// try{ -// doUnbindService(); -// }catch(Throwable tr){ -// Log.e(TAG, "", tr); -// } } private CharSequence throwableToString(Throwable tr) { @@ -122,24 +118,27 @@ public class I2PDActivity extends Activity { }; - private boolean mIsBound; + private static volatile boolean mIsBound; - private synchronized void doBindService() { - if(mIsBound)return; - // Establish a connection with the service. We use an explicit - // class name because we want a specific service implementation that - // we know will be running in our own process (and thus won't be - // supporting component replacement by other applications). - bindService(new Intent(this, - ForegroundService.class), mConnection, Context.BIND_AUTO_CREATE); - mIsBound = true; + private void doBindService() { + synchronized (I2PDActivity.class) { + if (mIsBound) return; + // Establish a connection with the service. We use an explicit + // class name because we want a specific service implementation that + // we know will be running in our own process (and thus won't be + // supporting component replacement by other applications). + bindService(new Intent(this, ForegroundService.class), mConnection, Context.BIND_AUTO_CREATE); + mIsBound = true; + } } private void doUnbindService() { - if (mIsBound) { - // Detach our existing connection. - unbindService(mConnection); - mIsBound = false; + synchronized (I2PDActivity.class) { + if (mIsBound) { + // Detach our existing connection. + unbindService(mConnection); + mIsBound = false; + } } } @@ -177,9 +176,9 @@ public class I2PDActivity extends Activity { } } - private Timer gracefulQuitTimer; - private final Object gracefulQuitTimerLock = new Object(); - private synchronized void i2pdGracefulStop() { + private volatile Timer gracefulQuitTimer; + + private void i2pdGracefulStop() { if(daemon.getState()==DaemonSingleton.State.stopped){ Toast.makeText(this, R.string.already_stopped, Toast.LENGTH_SHORT).show(); @@ -218,18 +217,14 @@ public class I2PDActivity extends Activity { } } - },"gracQuitInit").start(); + },"gracInit").start(); } private Timer getGracefulQuitTimer() { - synchronized (gracefulQuitTimerLock) { - return gracefulQuitTimer; - } + return gracefulQuitTimer; } private void setGracefulQuitTimer(Timer gracefulQuitTimer) { - synchronized (gracefulQuitTimerLock) { - this.gracefulQuitTimer = gracefulQuitTimer; - } + this.gracefulQuitTimer = gracefulQuitTimer; } }