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:
parent
bbeecc8777
commit
a834edb2bd
3 changed files with 46 additions and 23 deletions
|
@ -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();
|
||||||
|
|
|
@ -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.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue