diff --git a/app/src/main/java/com/nutomic/syncthingandroid/model/Completion.java b/app/src/main/java/com/nutomic/syncthingandroid/model/Completion.java index 56e1733b..5e866635 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/model/Completion.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/model/Completion.java @@ -17,6 +17,8 @@ public class Completion { private static final String TAG = "Completion"; + private static final Boolean ENABLE_VERBOSE_LOG = false; + HashMap> deviceFolderMap = new HashMap>(); @@ -55,14 +57,18 @@ public class Completion { } } for (String deviceId : removedDevices) { - Log.v(TAG, "updateFromConfig: Remove device '" + deviceId + "' from cache model"); + if (ENABLE_VERBOSE_LOG) { + Log.v(TAG, "updateFromConfig: Remove device '" + deviceId + "' from cache model"); + } deviceFolderMap.remove(deviceId); } // Handle devices that were added to the config. for (Device device : newDevices) { if (!deviceFolderMap.containsKey(device.deviceID)) { - Log.v(TAG, "updateFromConfig: Add device '" + device.deviceID + "' to cache model"); + if (ENABLE_VERBOSE_LOG) { + Log.v(TAG, "updateFromConfig: Add device '" + device.deviceID + "' to cache model"); + } deviceFolderMap.put(device.deviceID, new HashMap()); } } @@ -85,7 +91,9 @@ public class Completion { } } for (String folderId : removedFolders) { - Log.v(TAG, "updateFromConfig: Remove folder '" + folderId + "' from cache model"); + if (ENABLE_VERBOSE_LOG) { + Log.v(TAG, "updateFromConfig: Remove folder '" + folderId + "' from cache model"); + } removeFolder(folderId); } @@ -96,8 +104,10 @@ public class Completion { // folder is shared with device. folderMap = deviceFolderMap.get(device.deviceID); if (!folderMap.containsKey(folder.id)) { - Log.v(TAG, "updateFromConfig: Add folder '" + folder.id + - "' shared with device '" + device.deviceID + "' to cache model."); + if (ENABLE_VERBOSE_LOG) { + Log.v(TAG, "updateFromConfig: Add folder '" + folder.id + + "' shared with device '" + device.deviceID + "' to cache model."); + } folderMap.put(folder.id, new CompletionInfo()); } } diff --git a/app/src/main/java/com/nutomic/syncthingandroid/service/EventProcessor.java b/app/src/main/java/com/nutomic/syncthingandroid/service/EventProcessor.java index aebf5d14..7182d267 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/service/EventProcessor.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/service/EventProcessor.java @@ -37,6 +37,8 @@ public class EventProcessor implements Runnable, RestApi.OnReceiveEventListener private static final String TAG = "EventProcessor"; + private static final Boolean ENABLE_VERBOSE_LOG = false; + /** * Minimum interval in seconds at which the events are polled from syncthing and processed. * This intervall will not wake up the device to save battery power. @@ -96,7 +98,7 @@ public class EventProcessor implements Runnable, RestApi.OnReceiveEventListener switch (event.type) { case "ConfigSaved": if (mRestApi != null) { - Log.v(TAG, "Forwarding ConfigSaved event to RestApi to get the updated config."); + Log.d(TAG, "Forwarding ConfigSaved event to RestApi to get the updated config."); mRestApi.reloadConfig(); } break; @@ -162,12 +164,12 @@ public class EventProcessor implements Runnable, RestApi.OnReceiveEventListener case "Starting": case "StartupComplete": case "StateChanged": - if (BuildConfig.DEBUG) { + if (ENABLE_VERBOSE_LOG) { Log.v(TAG, "Ignored event " + event.type + ", data " + event.data); } break; default: - Log.v(TAG, "Unhandled event " + event.type); + Log.d(TAG, "Unhandled event " + event.type); } } diff --git a/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingService.java b/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingService.java index 21ab0ef2..3ed78d10 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingService.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingService.java @@ -121,11 +121,6 @@ public class SyncthingService extends Service { public static final String EXTRA_STOP_AFTER_CRASHED_NATIVE = "com.nutomic.syncthingandroid.service.SyncthingService.EXTRA_STOP_AFTER_CRASHED_NATIVE"; - - public interface OnSyncthingKilled { - void onKilled(); - } - public interface OnServiceStateChangeListener { void onServiceStateChange(State currentState); } @@ -284,7 +279,8 @@ public class SyncthingService extends Service { } if (ACTION_RESTART.equals(intent.getAction()) && mCurrentState == State.ACTIVE) { - shutdown(State.INIT, () -> launchStartupTask(SyncthingRunnable.Command.main)); + shutdown(State.INIT); + launchStartupTask(SyncthingRunnable.Command.main); } else if (ACTION_STOP.equals(intent.getAction())) { if (intent.getBooleanExtra(EXTRA_STOP_AFTER_CRASHED_NATIVE, false)) { /** @@ -294,25 +290,49 @@ public class SyncthingService extends Service { * instance forcefully. */ mCurrentState = State.ERROR; - shutdown(State.DISABLED, () -> {}); + shutdown(State.DISABLED); } else { // Graceful shutdown. if (mCurrentState == State.STARTING || mCurrentState == State.ACTIVE) { - shutdown(State.DISABLED, () -> {}); + shutdown(State.DISABLED); } } } else if (ACTION_RESET_DATABASE.equals(intent.getAction())) { + /** + * 1. Stop syncthing native if it's running. + * 2. Reset the database, syncthing native will exit after performing the reset. + * 3. Relaunch syncthing native if it was previously running. + */ Log.i(TAG, "Invoking reset of database"); - shutdown(State.INIT, () -> { - new SyncthingRunnable(this, SyncthingRunnable.Command.resetdatabase).run(); + if (mCurrentState != State.DISABLED) { + // Shutdown synchronously. + shutdown(State.DISABLED); + } + new SyncthingRunnable(this, SyncthingRunnable.Command.resetdatabase).run(); + if (mLastDeterminedShouldRun) { launchStartupTask(SyncthingRunnable.Command.main); - }); + } } else if (ACTION_RESET_DELTAS.equals(intent.getAction())) { + /** + * 1. Stop syncthing native if it's running. + * 2. Reset delta index, syncthing native will NOT exit after performing the reset. + * 3. If syncthing was previously NOT running: + * 3.1 Schedule a shutdown of the native binary after it left State.STARTING (to State.ACTIVE). + * This is the moment, when the reset delta index work was completed and Web UI came up. + * 3.2 The shutdown gets deferred until State.ACTIVE was reached and then syncthing native will + * be shutdown synchronously. + */ Log.i(TAG, "Invoking reset of delta indexes"); - shutdown(State.INIT, () -> { - launchStartupTask(SyncthingRunnable.Command.resetdeltas); - }); + if (mCurrentState != State.DISABLED) { + // Shutdown synchronously. + shutdown(State.DISABLED); + } + launchStartupTask(SyncthingRunnable.Command.resetdeltas); + if (!mLastDeterminedShouldRun) { + // Shutdown if syncthing was not running before the UI action was raised. + shutdown(State.DISABLED); + } } else if (ACTION_REFRESH_NETWORK_INFO.equals(intent.getAction())) { mRunConditionMonitor.updateShouldRunDecision(); } else if (ACTION_IGNORE_DEVICE.equals(intent.getAction()) && mCurrentState == State.ACTIVE) { @@ -361,8 +381,7 @@ public class SyncthingService extends Service { return; } Log.v(TAG, "Stopping syncthing"); - shutdown(State.DISABLED, () -> { - }); + shutdown(State.DISABLED); } } } @@ -585,29 +604,28 @@ public class SyncthingService extends Service { mDestroyScheduled = true; } else { Log.i(TAG, "Shutting down syncthing binary immediately"); - shutdown(State.DISABLED, () -> { - }); + shutdown(State.DISABLED); } } } else { // If the storage permission got revoked, we did not start the binary and // are in State.INIT requiring an immediate shutdown of this service class. Log.i(TAG, "Shutting down syncthing binary due to missing storage permission."); - shutdown(State.DISABLED, () -> { - }); + shutdown(State.DISABLED); } super.onDestroy(); } /** - * Stop Syncthing and all helpers like event processor and api handler. - * Sets {@link #mCurrentState} to newState, and calls onKilledListener once Syncthing is killed. + * Stop SyncthingNative and all helpers like event processor and api handler. + * Sets {@link #mCurrentState} to newState. + * Performs a synchronous shutdown of the native binary. */ - private void shutdown(State newState, OnSyncthingKilled onKilledListener) { + private void shutdown(State newState) { if (mCurrentState == State.STARTING) { Log.w(TAG, "Deferring shutdown until State.STARTING was left"); mHandler.postDelayed(() -> { - shutdown(newState, onKilledListener); + shutdown(newState); }, 1000); return; } @@ -646,7 +664,6 @@ public class SyncthingService extends Service { } mSyncthingRunnable = null; } - onKilledListener.onKilled(); } public @Nullable @@ -740,8 +757,7 @@ public class SyncthingService extends Service { Log.v(TAG, "exportConfig BEGIN"); // Shutdown synchronously. - shutdown(State.DISABLED, () -> { - }); + shutdown(State.DISABLED); // Copy config, privateKey and/or publicKey to export path. Constants.EXPORT_PATH_OBJ.mkdirs(); @@ -843,8 +859,7 @@ public class SyncthingService extends Service { Log.v(TAG, "importConfig BEGIN"); // Shutdown synchronously. - shutdown(State.DISABLED, () -> { - }); + shutdown(State.DISABLED); // Import config, privateKey and/or publicKey. try {