Android FileObserver–The Underlying inotify Mechanism and an Example

  Android FileObserver is an interface provided by Android OS to monitor file access and modification. It’s based on the Linux inotify file change notification system.

This blog will give a brief introduction to inotify and illustrate the usage of Android FileObserver API with an example.

inotify

inotify is a simple but powerful file change notification system. It’s a mechanism built into the Linux 2.6.13 kernel and above.

The mechanism is exposed to the userspace program through a set of 3 system calls, including inotify_init, inotify_add_watch and inotify_rm_watch.

These system calls are declared in /usr/include/sys/inotify.h. One needs to include the header file as below in order to use them.

#include <sys/inotify.h>

 

The inotify_init function has the following prototype,

int inotify_init (void);

 

This function will create an inotify instance and return a file descriptor which all events are read from. Each instance is associated with a unique, ordered queue for events.

The inotify_add_watch function is declared as,

int inotify_add_watch (int __fd, const char *__name, uint32_t __mask);

 

where __fd is the file descriptor returned from the inotify_init function, __name is the path to the object (either file or directory) to watch, and __mask indicates the types of event to watch. The return value can be used to refer to the watch added, called watch descriptor.

The inotify_rm_watch system call is declared as,

int inotify_rm_watch (int __fd, int __wd);

 

where __fd is the return value of inotify_init, and __wd is the return value of inotify_add_watch. This function will remove the watch from the queue.

With this set of system call and normal file IO operations, one can monitor the file changes in Linux system. Please refer reference 1 and 2 for further details of inotify.

Android FileObserver

Android FileObserver is based on FileObserver. It provides similar monitoring mechanism as inotify does. One thing worth-mentioning is that the API documentation says “If a directory is monitored, events will be triggered for all files and subdirectories (recursively) inside the monitored directory”, but the FileObserver API is actually not recursive.

In other words, a FileObserver is attached to a folder, then only the files and sub-folders inside it are monitored, but its sub sub-folders and files are not. For example, there is a folder B inside folder A, and a folder C inside folder B. If a FileObserver is created to monitor folder A, then any modifications done for folder B is detected, but not for folder C.

An Android Sample App Based on FileObserver

As FileObserver is an abstract class, one must create a subclass that extends FileObserver and implement the event handler onEvent(int, string).

Below is an example,

package roman10.tutorial.fileobserver;
 
   
import android.os.FileObserver;
 
   
public class MyFileObserver extends FileObserver {
    public String absolutePath;
 
   
    public MyFileObserver(String path) {
        super(path, FileObserver.ALL_EVENTS);
        absolutePath = path;
    }
 
   
    @Override
    public void onEvent(int event, String path) {
        if (path == null) {
            return;
        }
        //a new file or subdirectory was created under the monitored directory
        if ((FileObserver.CREATE & event)!=0) {
            FileAccessLogStatic.accessLogMsg += absolutePath + "/" + path + " is created\n";
        }
        //a file or directory was opened
        if ((FileObserver.OPEN & event)!=0) {
            FileAccessLogStatic.accessLogMsg += path + " is opened\n";
        }
        //data was read from a file
        if ((FileObserver.ACCESS & event)!=0) {
            FileAccessLogStatic.accessLogMsg += absolutePath + "/" + path + " is accessed/read\n";
        }
        //data was written to a file
        if ((FileObserver.MODIFY & event)!=0) {
            FileAccessLogStatic.accessLogMsg += absolutePath + "/" + path + " is modified\n";
        }
        //someone has a file or directory open read-only, and closed it
        if ((FileObserver.CLOSE_NOWRITE & event)!=0) {
            FileAccessLogStatic.accessLogMsg += path + " is closed\n";
        }
        //someone has a file or directory open for writing, and closed it 
        if ((FileObserver.CLOSE_WRITE & event)!=0) {
            FileAccessLogStatic.accessLogMsg += absolutePath + "/" + path + " is written and closed\n";
        }
        //[todo: consider combine this one with one below]
        //a file was deleted from the monitored directory
        if ((FileObserver.DELETE & event)!=0) {
            //for testing copy file
// FileUtils.copyFile(absolutePath + "/" + path);
            FileAccessLogStatic.accessLogMsg += absolutePath + "/" + path + " is deleted\n";
        }
        //the monitored file or directory was deleted, monitoring effectively stops
        if ((FileObserver.DELETE_SELF & event)!=0) {
            FileAccessLogStatic.accessLogMsg += absolutePath + "/" + " is deleted\n";
        }
        //a file or subdirectory was moved from the monitored directory
        if ((FileObserver.MOVED_FROM & event)!=0) {
            FileAccessLogStatic.accessLogMsg += absolutePath + "/" + path + " is moved to somewhere " + "\n";
        }
        //a file or subdirectory was moved to the monitored directory
        if ((FileObserver.MOVED_TO & event)!=0) {
            FileAccessLogStatic.accessLogMsg += "File is moved to " + absolutePath + "/" + path + "\n";
        }
        //the monitored file or directory was moved; monitoring continues
        if ((FileObserver.MOVE_SELF & event)!=0) {
            FileAccessLogStatic.accessLogMsg += path + " is moved\n";
        }
        //Metadata (permissions, owner, timestamp) was changed explicitly
        if ((FileObserver.ATTRIB & event)!=0) {
            FileAccessLogStatic.accessLogMsg += absolutePath + "/" + path + " is changed (permissions, owner, timestamp)\n";
        }
    }
}

Once the subclass is defined, one needs to create instances of this class in order to use it.

MyFileObserver fileOb = new MyFileObserver("/sdcard/testf/");

 

Similar to inotify_add_watch and inotify_remove_watch, one can call startWatching() and stopWatching() methods to start or stop monitoring.

fileOb.startWatching();
fileOb.stopWatching();

For a complete sample app which monitors the /sdcard directory of the Android OS, and output the results to screen, you can refer to my github repo here, or simply click here to download the source code zip file.

Below is a screenshot of the sample app.

device

Figure 1. Screenshot of File Modification Monitor

References

1. Kernel Korner – Intro to inotify: http://www.linuxjournal.com/article/8478

2. inotify – a powerful yet simple file change notification system:http://www.kernel.org/doc/Documentation/filesystems/inotify.txt

3. Android FileObserver API documentation:http://developer.android.com/reference/android/os/FileObserver.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值