1
0
Fork 0
mirror of https://github.com/syncthing/syncthing-android.git synced 2024-11-26 14:21:16 +00:00

Fix runtime left behind on app update (#31)

* Fix runtime left behind on app update

* Always kill runtime synchronously and run it asynchronously

* More log output
This commit is contained in:
Catfriend1 2018-08-25 21:35:00 +02:00 committed by GitHub
parent bbeecc8777
commit a834edb2bd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 46 additions and 23 deletions

View file

@ -169,6 +169,7 @@ public class DrawerFragment extends Fragment implements SyncthingService.OnServi
mActivity.closeDrawer(); mActivity.closeDrawer();
break; break;
case R.id.drawerActionExit: case R.id.drawerActionExit:
Log.i(TAG, "Exiting app on user request");
mActivity.stopService(new Intent(mActivity, SyncthingService.class)); mActivity.stopService(new Intent(mActivity, SyncthingService.class));
mActivity.finish(); mActivity.finish();
mActivity.closeDrawer(); mActivity.closeDrawer();

View file

@ -133,10 +133,14 @@ public class SyncthingRunnable implements Runnable {
? pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG) ? pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG)
: null; : null;
try { try {
if (wakeLock != null) if (wakeLock != null) {
wakeLock.acquire(); wakeLock.acquire();
increaseInotifyWatches(); }
/**
* Setup and run a new syncthing instance
*/
increaseInotifyWatches();
HashMap<String, String> targetEnv = buildEnvironment(); HashMap<String, String> targetEnv = buildEnvironment();
process = setupAndLaunch(targetEnv); process = setupAndLaunch(targetEnv);
@ -216,11 +220,13 @@ public class SyncthingRunnable implements Runnable {
} catch (IOException | InterruptedException e) { } catch (IOException | InterruptedException e) {
Log.e(TAG, "Failed to execute syncthing binary or read output", e); Log.e(TAG, "Failed to execute syncthing binary or read output", e);
} finally { } finally {
if (wakeLock != null) if (wakeLock != null) {
wakeLock.release(); wakeLock.release();
if (process != null) }
if (process != null) {
process.destroy(); process.destroy();
} }
}
// Restart syncthing if it exited unexpectedly while running on a separate thread. // Restart syncthing if it exited unexpectedly while running on a separate thread.
if (!returnStdOut && restartSyncthingNative) { if (!returnStdOut && restartSyncthingNative) {
@ -346,7 +352,7 @@ public class SyncthingRunnable implements Runnable {
int exitCode; int exitCode;
List<String> syncthingPIDs = getSyncthingPIDs(); List<String> syncthingPIDs = getSyncthingPIDs();
if (syncthingPIDs.isEmpty()) { if (syncthingPIDs.isEmpty()) {
Log.d(TAG, "killSyncthing: Found no more running instances of " + Constants.FILENAME_SYNCTHING_BINARY); Log.d(TAG, "killSyncthing: Found no running instances of " + Constants.FILENAME_SYNCTHING_BINARY);
return; return;
} }
for (String syncthingPID : syncthingPIDs) { for (String syncthingPID : syncthingPIDs) {
@ -358,6 +364,15 @@ public class SyncthingRunnable implements Runnable {
" exit code " + Integer.toString(exitCode)); " exit code " + Integer.toString(exitCode));
} }
} }
/**
* Wait for the syncthing instance to end.
*/
Log.v(TAG, "Waiting for all syncthing instances to end ...");
while (!getSyncthingPIDs().isEmpty()) {
SystemClock.sleep(50);
}
Log.v(TAG, "killSyncthing: Complete.");
} }
/** /**

View file

@ -236,18 +236,19 @@ public class SyncthingService extends Service {
} }
if (ACTION_RESTART.equals(intent.getAction()) && mCurrentState == State.ACTIVE) { if (ACTION_RESTART.equals(intent.getAction()) && mCurrentState == State.ACTIVE) {
shutdown(State.INIT, () -> launchStartupTask()); shutdown(State.INIT, () -> launchStartupTask(SyncthingRunnable.Command.main));
} else if (ACTION_STOP.equals(intent.getAction()) && mCurrentState == State.ACTIVE) { } else if (ACTION_STOP.equals(intent.getAction()) && mCurrentState == State.ACTIVE) {
shutdown(State.DISABLED, () -> {}); shutdown(State.DISABLED, () -> {});
} else if (ACTION_RESET_DATABASE.equals(intent.getAction())) { } else if (ACTION_RESET_DATABASE.equals(intent.getAction())) {
Log.i(TAG, "Invoking reset of database");
shutdown(State.INIT, () -> { shutdown(State.INIT, () -> {
new SyncthingRunnable(this, SyncthingRunnable.Command.resetdatabase).run(); new SyncthingRunnable(this, SyncthingRunnable.Command.resetdatabase).run();
launchStartupTask(); launchStartupTask(SyncthingRunnable.Command.main);
}); });
} else if (ACTION_RESET_DELTAS.equals(intent.getAction())) { } else if (ACTION_RESET_DELTAS.equals(intent.getAction())) {
Log.i(TAG, "Invoking reset of delta indexes");
shutdown(State.INIT, () -> { shutdown(State.INIT, () -> {
new SyncthingRunnable(this, SyncthingRunnable.Command.resetdeltas).run(); launchStartupTask(SyncthingRunnable.Command.resetdeltas);
launchStartupTask();
}); });
} else if (ACTION_REFRESH_NETWORK_INFO.equals(intent.getAction())) { } else if (ACTION_REFRESH_NETWORK_INFO.equals(intent.getAction())) {
mRunConditionMonitor.updateShouldRunDecision(); mRunConditionMonitor.updateShouldRunDecision();
@ -282,11 +283,7 @@ public class SyncthingService extends Service {
switch (mCurrentState) { switch (mCurrentState) {
case DISABLED: case DISABLED:
case INIT: case INIT:
// HACK: Make sure there is no syncthing binary left running from an improper launchStartupTask(SyncthingRunnable.Command.main);
// shutdown (eg Play Store update).
shutdown(State.INIT, () -> {
launchStartupTask();
});
break; break;
case STARTING: case STARTING:
case ACTIVE: case ACTIVE:
@ -309,10 +306,10 @@ public class SyncthingService extends Service {
/** /**
* Prepares to launch the syncthing binary. * Prepares to launch the syncthing binary.
*/ */
private void launchStartupTask () { private void launchStartupTask (SyncthingRunnable.Command srCommand) {
Log.v(TAG, "Starting syncthing"); Log.v(TAG, "Starting syncthing");
synchronized(mStateLock) { synchronized(mStateLock) {
if (mCurrentState != State.INIT) { if (mCurrentState != State.DISABLED && mCurrentState != State.INIT) {
Log.e(TAG, "launchStartupTask: Wrong state " + mCurrentState + " detected. Cancelling."); Log.e(TAG, "launchStartupTask: Wrong state " + mCurrentState + " detected. Cancelling.");
return; return;
} }
@ -324,7 +321,7 @@ public class SyncthingService extends Service {
return; return;
} }
onServiceStateChange(State.STARTING); onServiceStateChange(State.STARTING);
mStartupTask = new StartupTask(this); mStartupTask = new StartupTask(this, srCommand);
mStartupTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); mStartupTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} }
@ -334,9 +331,11 @@ public class SyncthingService extends Service {
*/ */
private static class StartupTask extends AsyncTask<Void, Void, Void> { private static class StartupTask extends AsyncTask<Void, Void, Void> {
private WeakReference<SyncthingService> refSyncthingService; private WeakReference<SyncthingService> refSyncthingService;
private SyncthingRunnable.Command srCommand;
StartupTask(SyncthingService context) { StartupTask(SyncthingService context, SyncthingRunnable.Command srCommand) {
refSyncthingService = new WeakReference<>(context); refSyncthingService = new WeakReference<>(context);
this.srCommand = srCommand;
} }
@Override @Override
@ -364,7 +363,7 @@ public class SyncthingService extends Service {
// Get a reference to the service if it is still there. // Get a reference to the service if it is still there.
SyncthingService syncthingService = refSyncthingService.get(); SyncthingService syncthingService = refSyncthingService.get();
if (syncthingService != null) { if (syncthingService != null) {
syncthingService.onStartupTaskCompleteListener(); syncthingService.onStartupTaskCompleteListener(srCommand);
} }
} }
} }
@ -372,19 +371,27 @@ public class SyncthingService extends Service {
/** /**
* Callback on {@link StartupTask#onPostExecute}. * Callback on {@link StartupTask#onPostExecute}.
*/ */
private void onStartupTaskCompleteListener() { private void onStartupTaskCompleteListener(SyncthingRunnable.Command srCommand) {
if (mApi == null) { if (mApi == null) {
mApi = new RestApi(this, mConfig.getWebGuiUrl(), mConfig.getApiKey(), mApi = new RestApi(this, mConfig.getWebGuiUrl(), mConfig.getApiKey(),
this::onApiAvailable, () -> onServiceStateChange(mCurrentState)); this::onApiAvailable, () -> onServiceStateChange(mCurrentState));
Log.i(TAG, "Web GUI will be available at " + mConfig.getWebGuiUrl()); Log.i(TAG, "Web GUI will be available at " + mConfig.getWebGuiUrl());
} }
// Start the syncthing binary. // Check mSyncthingRunnable lifecycle and create singleton.
if (mSyncthingRunnable != null || mSyncthingRunnableThread != null) { if (mSyncthingRunnable != null || mSyncthingRunnableThread != null) {
Log.e(TAG, "onStartupTaskCompleteListener: Syncthing binary lifecycle violated"); Log.e(TAG, "onStartupTaskCompleteListener: Syncthing binary lifecycle violated");
return; return;
} }
mSyncthingRunnable = new SyncthingRunnable(this, SyncthingRunnable.Command.main); mSyncthingRunnable = new SyncthingRunnable(this, srCommand);
/**
* Check if an old syncthing instance is still running.
* This happens after an in-place app upgrade. If so, end it.
*/
mSyncthingRunnable.killSyncthing();
// Start the syncthing binary in a separate thread.
mSyncthingRunnableThread = new Thread(mSyncthingRunnable); mSyncthingRunnableThread = new Thread(mSyncthingRunnable);
mSyncthingRunnableThread.start(); mSyncthingRunnableThread.start();
@ -643,7 +650,7 @@ public class SyncthingService extends Service {
} catch (IOException e) { } catch (IOException e) {
Log.w(TAG, "Failed to import config", e); Log.w(TAG, "Failed to import config", e);
} }
launchStartupTask(); launchStartupTask(SyncthingRunnable.Command.main);
}); });
return true; return true;
} }