第二十五节(关于文件状态的监听)

看下android中监听一个文件状态(修改、删除之类)的使用方式:

 FileObserver fileObserver=new FileObserver("filepath") {
            @Override
            public void onEvent(int event, String path) {

            }
        };

        //开始监听
        fileObserver.startWatching();

        //停止监听
        fileObserver.stopWatching();

FileObserver对文件实现的监听其实也是通过JNI方式来实现的,在FIleObserver.java中有四个native方法:

        private native int init();
        private native void observe(int fd);
        private native int startWatching(int fd, String path, int mask);
        private native void stopWatching(int fd, int wfd);

在调用fileObserver.startWatching();的时候

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

内部调用的是s_observetThread的方法,这个类在static代码块就完成了初始化操作,并调用了start方法开启线程,它本身是继承了Thread类

private static class ObserverThread extends Thread {
}
static {
        s_observerThread = new ObserverThread();
        s_observerThread.start();
    }
public ObserverThread() {
            super("FileObserver");
            m_fd = init();
        }

在构造函数中调用了native方法init()方法,此后利用调用start开启线程,在run方法中🈶调用了native的observe()方法。

public void run() {
            observe(m_fd);
        }

之后在startWatching中调用了native的第三个方法startWatching()

 public int startWatching(String path, int mask, FileObserver observer) {
            int wfd = startWatching(m_fd, path, mask);

            Integer i = new Integer(wfd);
            if (wfd >= 0) {
                synchronized (m_observers) {
                    m_observers.put(i, new WeakReference(observer));
                }
            }

            return i;
        }

第四个native方法自然是通过fileObserver.stopWatching()来间接调用的。
我们看下这四个native方法的具体实现:

/Users/huozhenpeng/Documents/android-6.0.0_r1/frameworks/base/core/jni

找到这个路径下的android_util_FileObserver.cpp文件

image.png

打开这个文件:

image.png

这种写法是动态注册,前面也有讲过

1、

我们打算模仿着四个方法来实现对app卸载的监听,例如在用户卸载之后,自动打开一个网页手机用户反馈信息。
android_os_fileobserver_init方法只做了一件事,调用jni内置的方法inotify_init();

image.png

这里有详细介绍

https://www.ibm.com/developerworks/cn/linux/l-inotifynew/index.html

image.png
image.png
image.png

2、

第二个native方法observe()实际调用的是android_os_fileobserver_observe()方法

image.png

3、

第三个native方法startWatching方法实际调用的是android_os_fileobserver_startWatching()方法

image.png

4、

第四个native方法stopWatching方法实际调用的是android_os_fileobserver_stopWatching()方法

image.png

我们看下inotify.h这个头文件

#ifndef _UAPI_LINUX_INOTIFY_H
#define _UAPI_LINUX_INOTIFY_H
#include <linux/fcntl.h>
#include <linux/types.h>
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct inotify_event {
 __s32 wd;
 __u32 mask;
 __u32 cookie;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 __u32 len;
 char name[0];
};
#define IN_ACCESS 0x00000001
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define IN_MODIFY 0x00000002
#define IN_ATTRIB 0x00000004
#define IN_CLOSE_WRITE 0x00000008
#define IN_CLOSE_NOWRITE 0x00000010
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define IN_OPEN 0x00000020
#define IN_MOVED_FROM 0x00000040
#define IN_MOVED_TO 0x00000080
#define IN_CREATE 0x00000100
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define IN_DELETE 0x00000200
#define IN_DELETE_SELF 0x00000400
#define IN_MOVE_SELF 0x00000800
#define IN_UNMOUNT 0x00002000
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define IN_Q_OVERFLOW 0x00004000
#define IN_IGNORED 0x00008000
#define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO)
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define IN_ONLYDIR 0x01000000
#define IN_DONT_FOLLOW 0x02000000
#define IN_EXCL_UNLINK 0x04000000
#define IN_MASK_ADD 0x20000000
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define IN_ISDIR 0x40000000
#define IN_ONESHOT 0x80000000
#define IN_ALL_EVENTS (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE |   IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM |   IN_MOVED_TO | IN_DELETE | IN_CREATE | IN_DELETE_SELF |   IN_MOVE_SELF)
#define IN_CLOEXEC O_CLOEXEC
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define IN_NONBLOCK O_NONBLOCK
#endif

这里面描述了所有的可以监听的文件的状态和一个结构体inotify_event

代码:
native-lib.cpp

#include <jni.h>
#include <string>
#include <sys/inotify.h>

#include <fcntl.h>

#include <errno.h>

//android输出日志使用
#include <android/log.h>
#define LOG_TAG "file"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

extern "C"
JNIEXPORT void JNICALL
Java_com_example_huozhenpeng_fileobserver_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject job,jstring pathStr) {

    pid_t pid=fork();
    if(pid==0)
    {
        LOGE("fork子进程成功");

        int fd=inotify_init();

        const char *path=env->GetStringUTFChars(pathStr,NULL);
        int wd = inotify_add_watch(fd, path, IN_MODIFY);                  //监控指定文件的ALL_EVENTS。
        char event_buf[512];
        struct inotify_event* event;

        while (1)
        {
            int event_pos = 0;
            int num_bytes = read(fd, event_buf, sizeof(event_buf));
            LOGE("文件正在更改");
            if (num_bytes < (int)sizeof(*event))
            {
                if (errno == EINTR)
                    continue;

                LOGE("***** 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);
                }
                LOGE("文件有更改");
//                这个是回调到java层的,利用java代码构造FileObserver的时候不是覆写了个方法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;
            }
        }




    }
    std::string hello = "Hello from C++";
    return ;
}

MainActivity.java

package com.example.huozhenpeng.fileobserver;

import android.os.Environment;
import android.os.FileObserver;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    private  String path;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);



        // Example of a call to a native method
        TextView tv = (TextView) findViewById(R.id.sample_text);
         path= getCacheDir()+ File.separator+"observer.txt";
        File file=new File(path);
        if(!file.exists())
        {
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        FileObserver fileObserver=new FileObserver(path,FileObserver.MODIFY) {
            @Override
            public void onEvent(int event, String path) {

                Log.e("abc","文件有修改");
            }
        };
//        fileObserver.startWatching();
//        fileObserver.stopWatching();
        stringFromJNI(path);
        tv.setText("abc");
    }

    public void write(View view)
    {
        writeFile(path,"文本");
    }

    BufferedWriter out = null;
    public  void writeFile(String file, String conent) {

        try {
            out = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(file, true)));
            out.write(conent);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


        /**
         * A native method that is implemented by the 'native-lib' native library,
         * which is packaged with this application.
         */
    public native void stringFromJNI(String path);
}

点击写入

image.png
image.png

比如说监听到卸载之后去打开一个网页:
我们直接监听/data/data/应用包名
但是验证的结果是5.0以上不起作用,应该是与fork进程有关

if (sdk < 17) {
                    execlp("am", "am", "start", "-a", "android.intent.action.VIEW", "-d",
                           "http://www.baidu.com",NULL);

                } else{
                    execlp("am", "am", "start","--user","0","-a", "android.intent.action.VIEW", "-d",
                           "http://www.baidu.com",NULL);
                }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容