12

I am using FileObserver to observe a directory for changes. The process works fine 90% of the time, but occasionally it fails.

Here is a working example of logcat:

04-23 21:12:03.873: V/ItemObserver(1663): Setting up new item observer for item 2
04-23 21:12:04.374: I/ItemObserver(1663): Received item event for item 2, event: 256, file: batch.get.47
04-23 21:12:07.866: I/ItemObserver(1663): Received item event for item 2, event: 512, file: batch.get.47
04-23 21:12:07.873: I/ItemObserver(1663): Received item event for item 2, event: 512, file: item.xml
04-23 21:12:07.883: I/ItemObserver(1663): Received item event for item 2, event: 256, file: item.xml
04-23 21:12:08.033: I/ItemObserver(1663): Received item event for item 2, event: 8, file: item.xml

Here is a failed example:

04-23 22:08:09.403: V/ItemObserver(1751): Setting up new item observer for item 2
04-23 22:08:09.813: I/ItemObserver(1751): Received item event for item 2, event: 256, file: batch.get.52
04-23 22:08:09.954: I/ItemObserver(1751): Received item event for item 2, event: 32768, file: null

Once I get the 32768 event with a null file, everything stops. I've checked the source for FileObserver and searched for inotify 32768 and can't find where this is referenced anywhere.

The code to set up the observer is as follows:

itemDirObserver = new FileObserver(getItemsCache().getProcessedItemDir(itemId).getPath(), 
FileObserver.CLOSE_WRITE | FileObserver.CREATE | FileObserver.DELETE) {
  @Override
  public void onEvent(int event, final String file) {
    itemDirChanged(event, file);
  }
};
itemDirObserver.startWatching();

The code for the logcat is:

public synchronized void itemDirChanged(int event, String file) {
  Log.i(LOG, "Received item event for item " + itemId + ", event: " + event + ", file: " + file);
  switch (event) {
<snip>

Any idea what 32768 and null file signifies?

mvsjes2
  • 1,254
  • 2
  • 14
  • 23
  • I decided to file this as a bug: http://code.google.com/p/android/issues/detail?id=29546&q=FileObserver&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars – mvsjes2 Apr 25 '12 at 22:11
  • check this question: http://stackoverflow.com/questions/2452661/file-observer-problem – Ciprian May 10 '12 at 13:08
  • Thanks. The problem appears to be that even after stopWatching is called, you can get multiple 32768 events in your callback before your observer object is garbage collected, so you need to ingore events in your observer class after you have called stopWatching. IMO, after stopWatching is called you should not have to worry about it any more. The FileObserver class certainly needs to be updated to be more in sync with inotify. – mvsjes2 Jun 01 '12 at 15:13

4 Answers4

10

Thanks to this answer.

The event codes are listed here.

32768 in particular is this:

#define IN_IGNORED 0x00008000 /* File was ignored */

Community
  • 1
  • 1
dokkaebi
  • 9,004
  • 3
  • 42
  • 60
  • But do you know what 'IN_IGNORED' actually means? Does it mean that the fileobserver isn't watching it anymore? – Andrew Shepherd Nov 30 '14 at 22:29
  • 1
    I don't know much about it, tbh, but I found this: http://stackoverflow.com/a/4665947/931277. Looks like one cause is the node being deleted. It does mean you won't receive further events for that node. – dokkaebi Dec 01 '14 at 20:19
  • 1
    IN_IGNORED is triggered when: an inotify watch is removed (e.g. when a FileObserver is closed), when a file (and all hard links to it) are deleted or when the partition, containing a file, is unmounted (unlike holding an open file descriptor, your program won't be killed if you just monitor a file via inotify). – user1643723 Dec 27 '16 at 09:08
  • The link you provided is dead. This comment is long 'cos... SO. – vesperto May 31 '21 at 16:17
1

I too was suffering from occasional failures.

I discovered a big gotcha with the Android FileObserver: you mustn't have two FileObservers watching the same folder in your application.

If you call StopWatching on one FileObserver, any other FileObserver that is watching the same folder will also stop watching.

Andrew Shepherd
  • 44,254
  • 30
  • 139
  • 205
  • 1
    This is a bug in `FileObserver` (it has many more bugs than that…): if you try to add a watch for a file, when another watch for that inode already exists, Linux inotify API will return existing watch. This is not accounted for in FileObserver source code. Adding multiple watches for the same file/directory or adding a watches for different hard links to the same file (which share the inode) will trigger the observed behavior. – user1643723 Dec 27 '16 at 09:05
1

I had the problem that my FileObserver gets 32768 event and stops working. I desperately tried to understand how to fix this (without recreating the FileObserver) for a couple of days.

First I found that although I have a hard reference to my FileObserver this event (32768) can be triggered by garbage collection (when I forced it through DDMS).

Eventually I found that there was another FileObserver in my program to the same folder. As soon as I deleted it everything started working.

Do anybody knows if it is legal to have several observers to the same directory? I couldn't find any information about it

Eugene
  • 143
  • 10
0

The event in onEvent() doesn't returns exact the number as doc, you need to wrap as below

public void onEvent(int event, String path) {

        if ((FileObserver.CREATE & event)!=0) {
            PUtils.log("CREATE: " + rootPath + path);
        } else if ((FileObserver.MODIFY & event)!=0) {
            PUtils.log("MODIFY: " + rootPath + path);
        } else if ((FileObserver.DELETE & event)!=0) {
            PUtils.log("DELETE: " + rootPath + path);
        } else if ((FileObserver.DELETE_SELF & event)!=0) {
            PUtils.log("DELETE_SELF: " + rootPath + path);
        } else if ((FileObserver.MOVED_FROM & event)!=0) {
            PUtils.log("MOVED_FROM: " + rootPath + path);
        } else if ((FileObserver.MOVED_TO & event)!=0) {
            PUtils.log("MOVED_TO: " + rootPath + path);
        } else if ((FileObserver.MOVE_SELF & event)!=0) {
            PUtils.log("MOVE_SELF: " + rootPath + path);
        } else {
            PUtils.log("Unhandled event " + event + rootPath + path);
        }
thanhbinh84
  • 17,876
  • 6
  • 62
  • 69
  • I am intrigued that this seems to be working for me. Can you explain why the wrapper needed? – Adi Aug 03 '19 at 13:19
  • 1
    It returns binary number, so you have to use bitwise operator (&) to compare. https://www.tutorialspoint.com/java/java_basic_operators. You can log the return number case by case to view the value in detail. – thanhbinh84 Aug 06 '19 at 03:58