Android文件监控FileObserver介绍

在前面的Linux文件系统Inotify机制中介绍了Linux对文件变更监控过程。Android系统在此基础上封装了一个FileObserver类来方便使用Inotify机制。FileObserver是一个抽象类,需要定义子类实现该类的onEvent抽象方法,当被监控的文件或者目录发生变更事件时,将回调FileObserver的onEvent()函数来处理文件或目录的变更事件。

事件监控过程

在FileObserver类中定义了一个静态内部类ObserverThread,该线程类才是真正实现文件或目录监控过程。各种类型的FileObserver都拥有一个ObserverThread实例:

frameworks\base\core\java\android\os\FileObserver.java

public abstract class FileObserver {
    //可监控的事件类型
	public static final int ALL_EVENTS = ACCESS | MODIFY | ATTRIB | CLOSE_WRITE
            | CLOSE_NOWRITE | OPEN | MOVED_FROM | MOVED_TO | DELETE | CREATE | DELETE_SELF | MOVE_SELF;
	//静态创建并启动一个文件监控线程
	private static ObserverThread s_observerThread;
    static {
        s_observerThread = new ObserverThread();
        s_observerThread.start();
    }
    // instance
    private String m_path;
    private Integer m_descriptor;
    private int m_mask;
}

FileObserver类通过静态方式构造了一个ObserverThread对象:

public ObserverThread() {
	super("FileObserver");
	m_fd = init();//初始化一个inotify实例,Observer线程就是对该inotify实例进行监控
}

frameworks\base\core\jni\android_util_FileObserver.cpp

static jint android_os_fileobserver_init(JNIEnv* env, jobject object)
{
#ifdef HAVE_INOTIFY
    return (jint)inotify_init();//初始化一个inotify实例
#else // HAVE_INOTIFY
    return -1;
#endif // HAVE_INOTIFY
}

inotify_init()函数实现在Linux文件系统Inotify机制有详细介绍,然后启动ObserverThread线程,ObserverThread线程运行体:

frameworks\base\core\java\android\os\FileObserve$ObserverThread

public void run() {
	observe(m_fd);//监控inotify实例句柄
}

frameworks\base\core\jni\android_util_FileObserver.cpp

static void android_os_fileobserver_observe(JNIEnv* env, jobject object, jint fd)
{
#ifdef HAVE_INOTIFY
    char event_buf[512];//定义事件数组
    struct inotify_event* event;
    while (1)
    {
        int event_pos = 0;
		//从inotify实例句柄中读取事件
        int num_bytes = read(fd, event_buf, sizeof(event_buf));
        if (num_bytes < (int)sizeof(*event))
        {
            if (errno == EINTR)
                continue;
            ALOGE("***** ERROR! android_os_fileobserver_observe() got a short event!");
            return;
        }
	    //循环处理读取到的事件
        while (num_bytes >= (int)sizeof(*event))
        {
            int event_size;
            event = (struct inotify_event *)(event_buf + event_pos);
            jstring path = NULL;
            if (event->len > 0)
            {
                path = env->NewStringUTF(event->name);
            }
			//调用ObserverThread的onEvent函数通知上层响应
            env->CallVoidMethod(object, method_onEvent, event->wd, event->mask, path);
            if (env->ExceptionCheck()) {
                env->ExceptionDescribe();
                env->ExceptionClear();
            }
            if (path != NULL)
            {
                env->DeleteLocalRef(path);
            }
            event_size = sizeof(*event) + event->len;
            num_bytes -= event_size;
            event_pos += event_size;
        }
    }
#endif // HAVE_INOTIFY
}

ObserverThread线程循环从inotify实例句柄中读取事件,然后回调ObserverThread的onEvent函数来处理事件。

frameworks\base\core\java\android\os\FileObserve$ObserverThread

public void onEvent(int wfd, int mask, String path) {
	// look up our observer, fixing up the map if necessary...
	FileObserver observer = null;
	synchronized (m_observers) {
		//根据wfd句柄从m_observers表中查找出注册的FileObserver对象
		WeakReference weak = m_observers.get(wfd);
		if (weak != null) {  // can happen with lots of events from a dead wfd
			observer = (FileObserver) weak.get();
			if (observer == null) {
				m_observers.remove(wfd);
			}
		}
	}
	// ...then call out to the observer without the sync lock held
	if (observer != null) {
		try {
			//调用对应的FileObserver对象的onEvent函数来处理事件
			observer.onEvent(mask, path);
		} catch (Throwable throwable) {
			Log.wtf(LOG_TAG, "Unhandled exception in FileObserver " + observer, throwable);
		}
	}
}

注册监控watch

FileObserver类提供了startWatching()函数来启动文件监控

frameworks\base\core\java\android\os\FileObserver.java

public void startWatching() {
	if (m_descriptor < 0) {
		m_descriptor = s_observerThread.startWatching(m_path, m_mask, this);
	}
}

由ObserverThread线程对象启动监控

frameworks\base\core\java\android\os\FileObserver$ObserverThread

public int startWatching(String path, int mask, FileObserver observer) {
	//在Inotify实例中添加一个watch对象,并得到一个watch对象句柄
	int wfd = startWatching(m_fd, path, mask);
	Integer i = new Integer(wfd);
	if (wfd >= 0) {
		//将watch对象句柄和响应该watch事件的FileObserver以键值对的形式保存在m_observers成员变量中
		synchronized (m_observers) {
			m_observers.put(i, new WeakReference(observer));
		}
	}
	return i;
}

ObserverThread又调用native方法android_os_fileobserver_startWatching()来添加一个watch

frameworks\base\core\jni\android_util_FileObserver.cpp

static jint android_os_fileobserver_startWatching(JNIEnv* env, jobject object, jint fd, jstring pathString, jint mask)
{
    int res = -1;
#ifdef HAVE_INOTIFY
    if (fd >= 0)
    {
        const char* path = env->GetStringUTFChars(pathString, NULL);
		//在Inotify实例上添加一个watch对象
        res = inotify_add_watch(fd, path, mask);
        env->ReleaseStringUTFChars(pathString, path);
    }
#endif // HAVE_INOTIFY
    return res;
}

注销监控watch

FileObserver类提供了使用stopWatching()函数来停止文件监控。

frameworks\base\core\java\android\os\FileObserver$ObserverThread

public void stopWatching() {
	if (m_descriptor >= 0) {
		s_observerThread.stopWatching(m_descriptor);
		m_descriptor = -1;
	}
}

frameworks\base\core\java\android\os\FileObserve$ObserverThread

public void stopWatching(int descriptor) {
	stopWatching(m_fd, descriptor);
}

frameworks\base\core\jni\android_util_FileObserver.cpp

static void android_os_fileobserver_stopWatching(JNIEnv* env, jobject object, jint fd, jint wfd)
{
#ifdef HAVE_INOTIFY
    inotify_rm_watch((int)fd, (uint32_t)wfd);
#endif // HAVE_INOTIFY
}

Android文件监控FileObserver介绍,布布扣,bubuko.com

时间: 2024-12-29 16:48:12

Android文件监控FileObserver介绍的相关文章

android.app.Activity 的介绍

发现当前Android的资料不是很多,而且对于Activity的介绍也很少,所以把官方文档的android.app.Activity的介绍翻译了一下,加入了一些自己的理解.各位如果觉得我自己理解的不对,请无视.欢迎邮件讨论. android.app public class android.app.Activity java.lang.Object android.content.Context android.app.ApplicationContext    ViewInflate.Fact

android 文件监听器

(1)程序说明 1)首先要添加文件创建,删除,和写入数据的权限 2)接着扩展fileobseerver,写SDk文件监听类.可以查看下文的文件监听器源码 3)如何启动文件监控? 对于Activity来说通常在onResume()方法中调用startwatching()来启动文件监控. 在onPause()方法中调用stopwatching()来取消文件监控. (2)布局文件 <?xml version="1.0" encoding="utf-8"?> &

关于Android四大基本组件介绍与生命周期(转)

Android四大基本组件介绍与生命周期 Android四大基本组件分别是Activity,Service服务,Content Provider内容提供者,BroadcastReceiver广播接收器. 一:了解四大基本组件 Activity : 应用程序中,一个Activity通常就是一个单独的屏幕,它上面可以显示一些控件也可以监听并处理用户的事件做出响应. Activity之间通过Intent进行通信.在Intent 的描述结构中,有两个最重要的部分:动作和动作对应的数据. 典型的动作类型有

【转】Android 4.2蓝牙介绍

原文网址:http://blog.csdn.net/innost/article/details/9187199 Tieto公司某蓝牙大牛写得<程序员>投稿文章 Android 4.2蓝牙介绍 蓝牙一词源于公元十世纪丹麦国王HaraldBlatand名字中的Blatand.Blatand的英文之意就是Blue tooth.这是因为这位让丹麦人引以为傲的国王酷爱吃蓝莓以至于牙龈都被染成蓝色.由于Blatand统一了丹麦和挪威,所以,作为无线通信技术的一种,蓝牙技术之所以取名Bluetooth可谓

Android开发进阶:如何读写Android文件

Android主要有四大主要组件组成:Activity.ContentProvider.Service.Intent组成.Android文件的运行主要需要读写四大组件的文件.本文将介绍如何读写Android文件,希望对正在进行Android开发的朋友有所帮助. 文件存放位置 在Android中文件的I/O是存放在/data/data/<package name>/file/filename目录下. 提示:Android是基于linux系统的,在linux的文件系统中不存在类似于Windows的

Android反编译工具介绍与简单实用方法

Android反编译工具介绍与简单实用方法 Android反编译的目的无非就是为了看到APK的xml.资源和代码: 得到代码的方式:直接解压APK文件 --> 得到classes.dex文件 --> 使用 dex2jar classes.dex classes.jar生成jar文件 --> [可选的解压jar文件] -->使用XJad或者JDCompiler查看源代码 得到XML的方式: 方式1:直接解压APK文件 --> 通过axmlprinter工具查看XML文件(这种方

Android 6.0 Marshmallow介绍

Android 6.0 Marshmallow介绍 Android 6.0 (M) 为用户和应用开发者提供了新功能.本文旨在介绍其中最值得关注的 API和重点介绍您应该了解并在开发应用时加以考虑的一些主要变更. 1.Android 6.0新增功能与特性 指纹身份验证: 此版本提供了一些新的 API,在受支持的设备上,用户只需扫描其指纹即可完成身份验证,这些 API 还可与 Android 密钥库系统结合使用. 要通过指纹扫描验证用户身份,请获取新 FingerprintManager 类的实例,

Android ViewPager实例代码介绍2。

以前写过一篇ViewPager:内容content+指示点的Demo: 这篇文章继续介绍ViewPager:内容content+标题title的Demo. 实现效果图: 源代码: 布局文件:activity_main: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"

zabbix之日志文件监控

一.日志item介绍 下面介绍zabbix另一个"重量级"的功能--日志文件监控,它最主要的是监控日志文件中有没有某个字符串的表达式,对应日志轮转与否,zabbix都支持. 在配置Item的时候,Type选择Zabbix agent (active),这里主要需要配置的是Key.下面是监控日志的两种key--log和logtr. log[/path/to/some/file,<regexp>,<encoding>,<maxlines>,<mod