stop file watching when service has been destroyed

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java  | 16 
src/main/java/eu/siacs/conversations/utils/ConversationsFileObserver.java | 24 
2 files changed, 35 insertions(+), 5 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -55,7 +55,6 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Hashtable;
@@ -256,6 +255,8 @@ public class XmppConnectionService extends Service {
         }
     };
 
+    private boolean destroyed = false;
+
     private int unreadCount = -1;
 
     //Ui callback listeners
@@ -963,6 +964,7 @@ public class XmppConnectionService extends Service {
     @SuppressLint("TrulyRandom")
     @Override
     public void onCreate() {
+        this.destroyed = false;
         OmemoSetting.load(this);
         ExceptionHelper.init(getApplicationContext());
         try {
@@ -1007,7 +1009,7 @@ public class XmppConnectionService extends Service {
         }
         if (Compatibility.hasStoragePermission(this)) {
             Log.d(Config.LOGTAG, "starting file observer");
-            new Thread(fileObserver::startWatching).start();
+            mFileAddingExecutor.execute(this.fileObserver::startWatching);
             mFileAddingExecutor.execute(this::checkForDeletedFiles);
         }
         if (Config.supportOpenPgp()) {
@@ -1047,9 +1049,17 @@ public class XmppConnectionService extends Service {
     }
 
     private void checkForDeletedFiles() {
+        if (destroyed) {
+            Log.d(Config.LOGTAG, "Do not check for deleted files because service has been destroyed");
+            return;
+        }
         final List<String> deletedUuids = new ArrayList<>();
         final List<DatabaseBackend.FilePath> relativeFilePaths = databaseBackend.getAllNonDeletedFilePath();
         for(final DatabaseBackend.FilePath filePath : relativeFilePaths) {
+            if (destroyed) {
+                Log.d(Config.LOGTAG, "Stop checking for deleted files because service has been destroyed");
+                return;
+            }
             final File file = fileBackend.getFileForPath(filePath.path);
             if (!file.exists()) {
                 deletedUuids.add(filePath.uuid.toString());
@@ -1096,8 +1106,8 @@ public class XmppConnectionService extends Service {
 
     public void restartFileObserver() {
         Log.d(Config.LOGTAG, "restarting file observer");
+        mFileAddingExecutor.execute(this.fileObserver::restartWatching);
         mFileAddingExecutor.execute(this::checkForDeletedFiles);
-        new Thread(fileObserver::restartWatching).start();
     }
 
     public void toggleScreenEventReceiver() {

src/main/java/eu/siacs/conversations/utils/ConversationsFileObserver.java 🔗

@@ -8,6 +8,7 @@ import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Stack;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import eu.siacs.conversations.Config;
 
@@ -21,16 +22,26 @@ public abstract class ConversationsFileObserver {
 
     private final String path;
     private final List<SingleFileObserver> mObservers = new ArrayList<>();
+    private final AtomicBoolean shouldStop = new AtomicBoolean(true);
 
     protected ConversationsFileObserver(String path) {
         this.path = path;
     }
 
-    public synchronized void startWatching() {
+    public void startWatching() {
+        shouldStop.set(false);
+        startWatchingInternal();
+    }
+
+    private synchronized void startWatchingInternal() {
         Stack<String> stack = new Stack<>();
         stack.push(path);
 
         while (!stack.empty()) {
+            if (shouldStop.get()) {
+                Log.d(Config.LOGTAG,"file observer received command to stop");
+                return;
+            }
             String parent = stack.pop();
             mObservers.add(new SingleFileObserver(parent, FileObserver.DELETE| FileObserver.MOVED_FROM));
             final File path = new File(parent);
@@ -39,6 +50,10 @@ public abstract class ConversationsFileObserver {
                 continue;
             }
             for(File file : files) {
+                if (shouldStop.get()) {
+                    Log.d(Config.LOGTAG,"file observer received command to stop");
+                    return;
+                }
                 if (file.isDirectory() && file.getName().charAt(0) != '.') {
                     final String currentPath = file.getAbsolutePath();
                     if (depth(file) <= 8 && !stack.contains(currentPath) && !observing(currentPath)) {
@@ -69,7 +84,12 @@ public abstract class ConversationsFileObserver {
         return false;
     }
 
-    public synchronized void stopWatching() {
+    public void stopWatching() {
+        shouldStop.set(true);
+        stopWatchingInternal();
+    }
+
+    private synchronized void stopWatchingInternal() {
         for(FileObserver observer : mObservers) {
             observer.stopWatching();
         }