1
0
Fork 0
mirror of https://github.com/syncthing/syncthing-android.git synced 2025-01-24 10:55:54 +00:00

Fix exit code 9 handling in SyncthingRunnable (#25)

Display syncthing native exit code on crash
This commit is contained in:
Catfriend1 2018-08-23 09:45:54 +02:00 committed by GitHub
parent fb0479e5f2
commit 8fea022982
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 110 additions and 71 deletions

View file

@ -168,10 +168,10 @@ public class NotificationHandler {
mNotificationManager.cancel(ID_PERSISTENT_WAITING);
}
public void showCrashedNotification(@StringRes int title) {
public void showCrashedNotification(@StringRes int title, String extraInfo) {
Intent intent = new Intent(mContext, LogActivity.class);
Notification n = getNotificationBuilder(mInfoChannel)
.setContentTitle(mContext.getString(title))
.setContentTitle(mContext.getString(title, extraInfo))
.setContentText(mContext.getString(R.string.notification_crash_text))
.setSmallIcon(R.drawable.ic_stat_notify)
.setContentIntent(PendingIntent.getActivity(mContext, 0, intent, 0))

View file

@ -109,9 +109,14 @@ public class SyncthingRunnable implements Runnable {
@SuppressLint("WakelockTimeout")
public String run(boolean returnStdOut) {
trimLogFile();
int ret;
Boolean sendStopToService = false;
Boolean restartSyncthingNative = false;
int exitCode;
String capturedStdOut = "";
// Trim Syncthing log.
trimLogFile();
// Make sure Syncthing is executable
try {
ProcessBuilder pb = new ProcessBuilder("chmod", "500", mSyncthingBinary.getPath());
@ -161,31 +166,52 @@ public class SyncthingRunnable implements Runnable {
niceSyncthing();
ret = process.waitFor();
Log.i(TAG, "Syncthing exited with code " + ret);
exitCode = process.waitFor();
Log.i(TAG, "Syncthing exited with code " + exitCode);
mSyncthing.set(null);
if (lInfo != null)
if (lInfo != null) {
lInfo.join();
if (lWarn != null)
}
if (lWarn != null) {
lWarn.join();
}
switch (ret) {
switch (exitCode) {
case 0:
case 137:
// Syncthing was shut down (via API or SIGKILL), do nothing.
Log.i(TAG, "Syncthing was shut down normally via API or SIGKILL. Exit code = " + exitCode);
break;
case 1:
Log.w(TAG, "Another Syncthing instance is already running, requesting restart via SyncthingService intent");
//fallthrough
Log.w(TAG, "exit reason = exitError. Another Syncthing instance may be already running.");
mNotificationHandler.showCrashedNotification(R.string.notification_crash_title, Integer.toString(exitCode));
sendStopToService = true;
break;
case 2:
// This should not happen as STNOUPGRADE is set.
Log.w(TAG, "exit reason = exitNoUpgradeAvailable. Another Syncthing instance may be already running.");
mNotificationHandler.showCrashedNotification(R.string.notification_crash_title, Integer.toString(exitCode));
sendStopToService = true;
break;
case 3:
// Restart was requested via Rest API call.
Log.i(TAG, "Restarting syncthing");
mContext.startService(new Intent(mContext, SyncthingService.class)
.setAction(SyncthingService.ACTION_RESTART));
Log.i(TAG, "exit reason = exitRestarting. Restarting syncthing.");
restartSyncthingNative = true;
break;
case 9:
// Native was force killed.
Log.w(TAG, "exit reason = exitForceKill.");
mNotificationHandler.showCrashedNotification(R.string.notification_crash_title, Integer.toString(exitCode));
sendStopToService = true;
break;
case 64:
Log.w(TAG, "exit reason = exitInvalidCommandLine.");
mNotificationHandler.showCrashedNotification(R.string.notification_crash_title, Integer.toString(exitCode));
sendStopToService = true;
break;
default:
Log.w(TAG, "Syncthing has crashed (exit code " + ret + ")");
mNotificationHandler.showCrashedNotification(R.string.notification_crash_title);
Log.w(TAG, "Syncthing exited unexpectedly. Exit code = " + exitCode);
mNotificationHandler.showCrashedNotification(R.string.notification_crash_title, Integer.toString(exitCode));
sendStopToService = true;
}
} catch (IOException | InterruptedException e) {
Log.e(TAG, "Failed to execute syncthing binary or read output", e);
@ -195,6 +221,20 @@ public class SyncthingRunnable implements Runnable {
if (process != null)
process.destroy();
}
// Restart syncthing if it exited unexpectedly while running on a separate thread.
if (!returnStdOut && restartSyncthingNative) {
mContext.startService(new Intent(mContext, SyncthingService.class)
.setAction(SyncthingService.ACTION_RESTART));
}
// Notify {@link SyncthingService} that service state State.ACTIVE is no longer valid.
if (!returnStdOut && sendStopToService) {
mContext.startService(new Intent(mContext, SyncthingService.class)
.setAction(SyncthingService.ACTION_STOP));
}
// Return captured command line output.
return capturedStdOut;
}
@ -299,37 +339,23 @@ public class SyncthingRunnable implements Runnable {
}
}
public interface OnSyncthingKilled {
void onKilled();
}
/**
* Look for running libsyncthing.so processes and kill them.
* Try a SIGINT first, then try again with SIGKILL.
* Look for running libsyncthing.so processes and end them gracefully.
*/
public void killSyncthing() {
for (int i = 0; i < 2; i++) {
List<String> syncthingPIDs = getSyncthingPIDs();
if (syncthingPIDs.isEmpty()) {
Log.d(TAG, "killSyncthing: Found no more running instances of " + Constants.FILENAME_SYNCTHING_BINARY);
break;
}
int exitCode;
for (String syncthingPID : syncthingPIDs) {
if (i > 0) {
// Force termination of the process by sending SIGKILL.
SystemClock.sleep(3000);
exitCode = Util.runShellCommand("kill -SIGKILL " + syncthingPID + "\n", mUseRoot);
} else {
exitCode = Util.runShellCommand("kill -SIGINT " + syncthingPID + "\n", mUseRoot);
SystemClock.sleep(1000);
}
if (exitCode == 0) {
Log.d(TAG, "Killed Syncthing process " + syncthingPID);
} else {
Log.w(TAG, "Failed to kill Syncthing process " + syncthingPID +
" exit code " + Integer.toString(exitCode));
}
int exitCode;
List<String> syncthingPIDs = getSyncthingPIDs();
if (syncthingPIDs.isEmpty()) {
Log.d(TAG, "killSyncthing: Found no more running instances of " + Constants.FILENAME_SYNCTHING_BINARY);
return;
}
for (String syncthingPID : syncthingPIDs) {
exitCode = Util.runShellCommand("kill -SIGINT " + syncthingPID + "\n", mUseRoot);
if (exitCode == 0) {
Log.d(TAG, "Sent kill SIGINT to process " + syncthingPID);
} else {
Log.w(TAG, "Failed to send kill SIGINT to process " + syncthingPID +
" exit code " + Integer.toString(exitCode));
}
}
}

View file

@ -44,6 +44,12 @@ public class SyncthingService extends Service {
public static final String ACTION_RESTART =
"com.nutomic.syncthingandroid.service.SyncthingService.RESTART";
/**
* Intent action to perform a Syncthing stop.
*/
public static final String ACTION_STOP =
"com.nutomic.syncthingandroid.service.SyncthingService.STOP";
/**
* Intent action to reset Syncthing's database.
*/
@ -95,6 +101,10 @@ public class SyncthingService extends Service {
public static final String EXTRA_FOLDER_ID =
"com.nutomic.syncthingandroid.service.SyncthingService.EXTRA_FOLDER_ID";
public interface OnSyncthingKilled {
void onKilled();
}
public interface OnServiceStateChangeListener {
void onServiceStateChange(State currentState);
}
@ -221,11 +231,14 @@ public class SyncthingService extends Service {
}
mNotificationHandler.updatePersistentNotification(this);
if (intent == null)
if (intent == null) {
return START_STICKY;
}
if (ACTION_RESTART.equals(intent.getAction()) && mCurrentState == State.ACTIVE) {
shutdown(State.INIT, () -> launchStartupTask());
} else if (ACTION_STOP.equals(intent.getAction()) && mCurrentState == State.ACTIVE) {
shutdown(State.DISABLED, () -> {});
} else if (ACTION_RESET_DATABASE.equals(intent.getAction())) {
shutdown(State.INIT, () -> {
new SyncthingRunnable(this, SyncthingRunnable.Command.resetdatabase).run();
@ -337,7 +350,7 @@ public class SyncthingService extends Service {
syncthingService.mConfig = new ConfigXml(syncthingService);
syncthingService.mConfig.updateIfNeeded();
} catch (ConfigXml.OpenConfigException e) {
syncthingService.mNotificationHandler.showCrashedNotification(R.string.config_read_failed);
syncthingService.mNotificationHandler.showCrashedNotification(R.string.config_read_failed, "ConfigXml.OpenConfigException");
synchronized (syncthingService.mStateLock) {
syncthingService.onServiceStateChange(State.ERROR);
}
@ -473,7 +486,7 @@ public class SyncthingService extends Service {
*
* Sets {@link #mCurrentState} to newState, and calls onKilledListener once Syncthing is killed.
*/
private void shutdown(State newState, SyncthingRunnable.OnSyncthingKilled onKilledListener) {
private void shutdown(State newState, OnSyncthingKilled onKilledListener) {
Log.i(TAG, "Shutting down background service");
synchronized(mStateLock) {
onServiceStateChange(newState);

View file

@ -349,7 +349,7 @@ Ens podeu informar dels problemes que trobeu a través de Github.</string>
<string name="default_folder_label">Càmera</string>
<!--ID of the default folder created on first start (camera folder). Must only contain 'a-z0-9_-'. Parameter is the device name-->
<string name="default_folder_id">%1$s-fotos</string>
<string name="notification_crash_title">El Syncthing s\'ha bloquejat</string>
<string name="notification_crash_title">El Syncthing s\'ha bloquejat %1$s</string>
<string name="notification_crash_text">Feu clic per veure els registres</string>
<string name="notifications_persistent_channel">El Syncthing està actiu</string>
<string name="notification_persistent_waiting_channel">Vigilant les condicions d\'execució</string>

View file

@ -327,7 +327,7 @@ Všechny zaznamenané chyby prosím hlašte přes Github.</string>
<string name="default_folder_label">Kamera</string>
<!--ID of the default folder created on first start (camera folder). Must only contain 'a-z0-9_-'. Parameter is the device name-->
<string name="default_folder_id">%1$s-foto</string>
<string name="notification_crash_title">Syncthing spadl</string>
<string name="notification_crash_title">Syncthing spadl %1$s</string>
<string name="notification_crash_text">Pro prohlížení logů klikněte</string>
<string name="notifications_other_channel">Ostatní upozornění</string>
<!--RestApi-->

View file

@ -314,7 +314,7 @@ Vær venlig at rapportere ethvert problem, du støder på, via Github. </string>
<string name="default_folder_label">Kamera</string>
<!--ID of the default folder created on first start (camera folder). Must only contain 'a-z0-9_-'. Parameter is the device name-->
<string name="default_folder_id">%1$s-fotos</string>
<string name="notification_crash_title">Syncthing crashede</string>
<string name="notification_crash_title">Syncthing crashede %1$s</string>
<string name="notification_crash_text">Klik for at se logs</string>
<!--RestApi-->
<!--Title of the notification shown when a restart is needed-->

View file

@ -366,7 +366,7 @@ Bitte melden Sie auftretende Probleme via GitHub.</string>
<string name="default_folder_label">Kamera</string>
<!--ID of the default folder created on first start (camera folder). Must only contain 'a-z0-9_-'. Parameter is the device name-->
<string name="default_folder_id">%1$s-Bilder</string>
<string name="notification_crash_title">Syncthing ist abgestürzt</string>
<string name="notification_crash_title">Syncthing ist abgestürzt (Exit-Code %1$s)</string>
<string name="notification_crash_text">Klicken um Logs anzuzeigen</string>
<string name="notifications_persistent_channel">Syncthing läuft</string>
<string name="notification_persistent_waiting_channel">Laufkonditionen werden überwacht</string>

View file

@ -318,7 +318,7 @@
<string name="default_folder_label">Φωτογραφική μηχανή</string>
<!--ID of the default folder created on first start (camera folder). Must only contain 'a-z0-9_-'. Parameter is the device name-->
<string name="default_folder_id">%1$s-photos</string>
<string name="notification_crash_title">Το Syncthing κατέρρευσε</string>
<string name="notification_crash_title">Το Syncthing κατέρρευσε %1$s</string>
<string name="notification_crash_text">Πατήστε για να δείτε την καταγραφή συμβάντων</string>
<string name="notifications_other_channel">Άλλες ειδοποιήσεις</string>
<!--RestApi-->

View file

@ -292,7 +292,7 @@
<string name="default_folder_label">Cámara</string>
<!--ID of the default folder created on first start (camera folder). Must only contain 'a-z0-9_-'. Parameter is the device name-->
<string name="default_folder_id">%1$s-photos</string>
<string name="notification_crash_title">Syncthing se ha estrellado</string>
<string name="notification_crash_title">Syncthing se ha estrellado %1$s</string>
<string name="notification_crash_text">Haga clic para ver los registros</string>
<!--RestApi-->
<!--Title of the notification shown when a restart is needed-->

View file

@ -288,7 +288,7 @@ Ilmoitathan ystävällisesti kaikista havaitsemistasi ongelmista Githubin kautta
<string name="default_folder_label">Kamera</string>
<!--ID of the default folder created on first start (camera folder). Must only contain 'a-z0-9_-'. Parameter is the device name-->
<string name="default_folder_id">%1$s-kuvat</string>
<string name="notification_crash_title">Syncthing kaatui</string>
<string name="notification_crash_title">Syncthing kaatui %1$s</string>
<!--RestApi-->
<!--Title of the notification shown when a restart is needed-->
<string name="restart_title">Uudelleenkäynnistys tarvitaan</string>

View file

@ -350,7 +350,7 @@ S\'il vous plaît, soumettez les problèmes que vous rencontrez via Github.</str
<string name="default_folder_label">Caméra</string>
<!--ID of the default folder created on first start (camera folder). Must only contain 'a-z0-9_-'. Parameter is the device name-->
<string name="default_folder_id">%1$s-photos</string>
<string name="notification_crash_title">Syncthing s\'est planté</string>
<string name="notification_crash_title">Syncthing s\'est planté %1$s</string>
<string name="notification_crash_text">Cliquer pour voir les journaux</string>
<string name="notifications_persistent_channel">Syncthing en marche</string>
<string name="notification_persistent_waiting_channel">Surveillance des conditions de fonctionnement</string>

View file

@ -352,7 +352,7 @@ VIGYÁZAT! Más alkalmazások kiolvashatják a backupból a titkos kulcsot, és
<string name="default_folder_label">Kamera</string>
<!--ID of the default folder created on first start (camera folder). Must only contain 'a-z0-9_-'. Parameter is the device name-->
<string name="default_folder_id">%1$s-kepek</string>
<string name="notification_crash_title">A Syncthing összeomlott</string>
<string name="notification_crash_title">A Syncthing összeomlott %1$s</string>
<string name="notification_crash_text">Koppints a naplók megtekintéséhez</string>
<string name="notifications_persistent_channel">Syncthing aktív</string>
<string name="notification_persistent_waiting_channel">Futási feltételek monitorozása</string>

View file

@ -350,7 +350,7 @@ Si prega di segnalare eventuali problemi che si incontrano via Github.</string>
<string name="default_folder_label">Camera</string>
<!--ID of the default folder created on first start (camera folder). Must only contain 'a-z0-9_-'. Parameter is the device name-->
<string name="default_folder_id">%1$s-photos</string>
<string name="notification_crash_title">Syncthing è andato in crash</string>
<string name="notification_crash_title">Syncthing è andato in crash %1$s</string>
<string name="notification_crash_text">Clicca per visualizzare i log</string>
<string name="notifications_persistent_channel">Syncthing attivo</string>
<string name="notification_persistent_waiting_channel">Monitoraggio delle condizioni di esecuzione</string>

View file

@ -315,7 +315,7 @@
<string name="default_folder_label">カメラ</string>
<!--ID of the default folder created on first start (camera folder). Must only contain 'a-z0-9_-'. Parameter is the device name-->
<string name="default_folder_id">%1$s-写真</string>
<string name="notification_crash_title">Syncthing がクラッシュしました</string>
<string name="notification_crash_title">Syncthing がクラッシュしました %1$s</string>
<string name="notification_crash_text">クリックしてログを表示</string>
<string name="notifications_other_channel">他の通知</string>
<!--RestApi-->

View file

@ -314,7 +314,7 @@
<string name="default_folder_label">카메라</string>
<!--ID of the default folder created on first start (camera folder). Must only contain 'a-z0-9_-'. Parameter is the device name-->
<string name="default_folder_id">%1$s-사진</string>
<string name="notification_crash_title">Syncthing이 충돌하였습니다.</string>
<string name="notification_crash_title">Syncthing이 충돌하였습니다. %1$s</string>
<string name="notification_crash_text">클릭해서 로그 보기</string>
<string name="notifications_other_channel">기타 알림</string>
<!--RestApi-->

View file

@ -350,7 +350,7 @@ Als je problemen tegenkomt, meld ze dan via GitHub.</string>
<string name="default_folder_label">Camera</string>
<!--ID of the default folder created on first start (camera folder). Must only contain 'a-z0-9_-'. Parameter is the device name-->
<string name="default_folder_id">%1$s-foto\'s</string>
<string name="notification_crash_title">Syncthing is gecrasht</string>
<string name="notification_crash_title">Syncthing is gecrasht %1$s</string>
<string name="notification_crash_text">Tik om logboeken te bekijken</string>
<string name="notifications_persistent_channel">Syncthing is actief</string>
<string name="notification_persistent_waiting_channel">Uitvoervoorwaarden controleren</string>

View file

@ -322,7 +322,7 @@ Proszę zgłaszać napotkane błędy programu za pośrednictwem serwisu Github.<
<string name="default_folder_label">Kamera</string>
<!--ID of the default folder created on first start (camera folder). Must only contain 'a-z0-9_-'. Parameter is the device name-->
<string name="default_folder_id">%1$s-zdjęcia</string>
<string name="notification_crash_title">Syncthing spadło z rowerka :(</string>
<string name="notification_crash_title">Syncthing spadło z rowerka %1$s</string>
<string name="notification_crash_text">Dotknij, by zobaczyć logi</string>
<string name="notifications_other_channel">Inne powiadomienia</string>
<!--RestApi-->

View file

@ -340,7 +340,7 @@ Por favor, nos avise sobre quaisquer problemas que você encontrar via Github.</
<string name="default_folder_label">Câmera</string>
<!--ID of the default folder created on first start (camera folder). Must only contain 'a-z0-9_-'. Parameter is the device name-->
<string name="default_folder_id">%1$s-fotos</string>
<string name="notification_crash_title">O Syncthing fechou inesperadamente</string>
<string name="notification_crash_title">O Syncthing fechou inesperadamente %1$s</string>
<string name="notification_crash_text">Clique para ver os logs</string>
<string name="notifications_persistent_channel">Syncthing ativado</string>
<string name="notification_persistent_waiting_channel">Monitorando condições de execução</string>

View file

@ -373,7 +373,7 @@ Vă rugăm să raportați orice problemă întâlniți, prin intermediul GitHub.
<string name="default_folder_label">Camera</string>
<!--ID of the default folder created on first start (camera folder). Must only contain 'a-z0-9_-'. Parameter is the device name-->
<string name="default_folder_id">%1$s-fotografii</string>
<string name="notification_crash_title">Syncthing s-a oprit neașteptat</string>
<string name="notification_crash_title">Syncthing s-a oprit neașteptat %1$s</string>
<string name="notification_crash_text">Atingeți pentru a vedea jurnalele de erori</string>
<string name="notifications_persistent_channel">Syncthing este activ</string>
<string name="notification_persistent_waiting_channel">Monitorizare condiții rulare</string>
@ -445,7 +445,7 @@ Vă rugăm să raportați orice problemă întâlniți, prin intermediul GitHub.
<string name="keep_versions_description">Numărul de versiuni vechi ale fișierelor ce vor fi păstrate, pentru fiecare fișier.</string>
<string name="simple_file_versioning_description">Fișierele sunt mutate și redenumite după dată în directorul .stversions atunci când sunt înlocuite sau șterse de către Syncthing.</string>
<string name="trashcan_versioning_description">Fișierele sunt mutate în directorul .stversions atunci când sunt înlocuite sau șterse de către Syncthing.</string>
<string name="staggered_versioning_description">Fișierele sunt mutate și redenumite după dată în directorul .stversions
<string name="staggered_versioning_description">Fișierele sunt mutate și redenumite după dată în directorul .stversions
atunci când sunt înlocuite sau șterse de către Syncthing. Versiunile sunt șterse automat dacă sunt mai vechi decât vârsta maximă sau dacă au depășit numărul de fișiere permise într-un interval.\n\nUrmătoarele intervale sunt folosite: în prima oră o versiune este păstrată pentru fiecare 30 de secunde, în prima zi o versiune este păstrată pentru fiecare oră, în primele 30 de zile o versiune este păstrată pentru fiecare zi, până la vârsta maximă o versiune este păstrată pentru fiecare săptămână.</string>
<string name="maximum_age_description">Intervalul de timp maxim de păstrat o versiune (în zile, setați la 0 pentru a păstra versiunile pentru totdeauna)</string>
<string name="versions_path_description">Calea unde versiunile vor fi stocate (lăsați gol pentru a folosi directorul implicit .stversions din directorul partajat)</string>

View file

@ -355,7 +355,7 @@
<string name="default_folder_label">Камера</string>
<!--ID of the default folder created on first start (camera folder). Must only contain 'a-z0-9_-'. Parameter is the device name-->
<string name="default_folder_id">%1$s фото</string>
<string name="notification_crash_title">Syncthing завершился из-за сбоя</string>
<string name="notification_crash_title">Syncthing завершился из-за сбоя %1$s</string>
<string name="notification_crash_text">Нажмите для просмотра логов</string>
<string name="notifications_persistent_channel">Syncthing работает</string>
<string name="notification_persistent_waiting_channel">Отслеживание условий работы</string>

View file

@ -368,7 +368,7 @@ Vänligen rapportera eventuella problem du stöter på via Github.</string>
<string name="default_folder_label">Kamera</string>
<!--ID of the default folder created on first start (camera folder). Must only contain 'a-z0-9_-'. Parameter is the device name-->
<string name="default_folder_id">%1$s foton</string>
<string name="notification_crash_title">Syncthing har kraschat</string>
<string name="notification_crash_title">Syncthing har kraschat %1$s</string>
<string name="notification_crash_text">Klicka för att visa loggar</string>
<string name="notifications_persistent_channel">Syncthing är aktiv</string>
<string name="notification_persistent_waiting_channel">Övervakar körvillkor</string>

View file

@ -243,7 +243,7 @@
<!--Label of the default folder created of first start (camera folder).-->
<string name="default_folder_label">Камера</string>
<!--ID of the default folder created on first start (camera folder). Must only contain 'a-z0-9_-'. Parameter is the device name-->
<string name="notification_crash_title">Роботу Syncthing аварійно завершено </string>
<string name="notification_crash_title">Роботу Syncthing аварійно завершено %1$s</string>
<!--RestApi-->
<!--Title of the notification shown when a restart is needed-->
<string name="restart_title">Необхідний перезапуск</string>

View file

@ -317,7 +317,7 @@
<string name="default_folder_label">摄像机</string>
<!--ID of the default folder created on first start (camera folder). Must only contain 'a-z0-9_-'. Parameter is the device name-->
<string name="default_folder_id">%1$s-照片</string>
<string name="notification_crash_title">Syncthing 已崩溃</string>
<string name="notification_crash_title">Syncthing 已崩溃 %1$s</string>
<string name="notification_crash_text">点击查看日志</string>
<string name="notifications_other_channel">其他通知</string>
<!--RestApi-->

View file

@ -314,7 +314,7 @@
<string name="default_folder_label">相機</string>
<!--ID of the default folder created on first start (camera folder). Must only contain 'a-z0-9_-'. Parameter is the device name-->
<string name="default_folder_id">%1$s-photos</string>
<string name="notification_crash_title">Syncthing 已經當機</string>
<string name="notification_crash_title">Syncthing 已經當機 %1$s</string>
<string name="notification_crash_text">觸碰檢視日誌</string>
<string name="notifications_other_channel">其他通知</string>
<!--RestApi-->

View file

@ -663,7 +663,7 @@ Please report any problems you encounter via Github.</string>
<!-- ID of the default folder created on first start (camera folder). Must only contain 'a-z0-9_-'. Parameter is the device name-->
<string name="default_folder_id">%1$s-photos</string>
<string name="notification_crash_title">Syncthing has crashed</string>
<string name="notification_crash_title">Syncthing has crashed (exit code %1$s)</string>
<string name="notification_crash_text">Click to view logs</string>