Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 31f977a4 authored by Sudheer Shanka's avatar Sudheer Shanka Committed by Android (Google) Code Review
Browse files

Merge "Update FileObserver to be able to watch multiple files."

parents 175e2f24 f7c79b4f
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -34408,8 +34408,12 @@ package android.os {
  }
  public abstract class FileObserver {
    ctor public FileObserver(String);
    ctor public FileObserver(String, int);
    ctor @Deprecated public FileObserver(String);
    ctor public FileObserver(@NonNull java.io.File);
    ctor public FileObserver(@NonNull java.util.List<java.io.File>);
    ctor @Deprecated public FileObserver(String, int);
    ctor public FileObserver(@NonNull java.io.File, int);
    ctor public FileObserver(@NonNull java.util.List<java.io.File>, int);
    method protected void finalize();
    method public abstract void onEvent(int, @Nullable String);
    method public void startWatching();
+83 −24
Original line number Diff line number Diff line
@@ -16,11 +16,15 @@

package android.os;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.Log;

import java.io.File;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

/**
 * Monitors files (using <a href="http://en.wikipedia.org/wiki/Inotify">inotify</a>)
@@ -28,7 +32,7 @@ import java.util.HashMap;
 * the device (including this one).  FileObserver is an abstract class;
 * subclasses must implement the event handler {@link #onEvent(int, String)}.
 *
 * <p>Each FileObserver instance monitors a single file or directory.
 * <p>Each FileObserver instance can monitor multiple files or directories.
 * If a directory is monitored, events will be triggered for all files and
 * subdirectories inside the monitored directory.</p>
 *
@@ -86,21 +90,32 @@ public abstract class FileObserver {
            observe(m_fd);
        }

        public int startWatching(String path, int mask, FileObserver observer) {
            int wfd = startWatching(m_fd, path, mask);
        public int[] startWatching(List<File> files, int mask, FileObserver observer) {
            final int count = files.size();
            final String[] paths = new String[count];
            for (int i = 0; i < count; ++i) {
                paths[i] = files.get(i).getAbsolutePath();
            }
            final int[] wfds = new int[count];
            Arrays.fill(wfds, -1);

            Integer i = new Integer(wfd);
            if (wfd >= 0) {
            startWatching(m_fd, paths, mask, wfds);

            final WeakReference<FileObserver> fileObserverWeakReference =
                    new WeakReference<>(observer);
            synchronized (m_observers) {
                    m_observers.put(i, new WeakReference(observer));
                for (int wfd : wfds) {
                    if (wfd >= 0) {
                        m_observers.put(wfd, fileObserverWeakReference);
                    }
                }
            }

            return i;
            return wfds;
        }

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

        public void onEvent(int wfd, int mask, String path) {
@@ -129,8 +144,8 @@ public abstract class FileObserver {

        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);
        private native void startWatching(int fd, String[] paths, int mask, int[] wfds);
        private native void stopWatching(int fd, int[] wfds);
    }

    private static ObserverThread s_observerThread;
@@ -141,15 +156,34 @@ public abstract class FileObserver {
    }

    // instance
    private String m_path;
    private Integer m_descriptor;
    private int m_mask;
    private final List<File> mFiles;
    private int[] mDescriptors;
    private final int mMask;

    /**
     * Equivalent to FileObserver(path, FileObserver.ALL_EVENTS).
     *
     * @deprecated use {@link #FileObserver(File)} instead.
     */
    @Deprecated
    public FileObserver(String path) {
        this(path, ALL_EVENTS);
        this(new File(path));
    }

    /**
     * Equivalent to FileObserver(file, FileObserver.ALL_EVENTS).
     */
    public FileObserver(@NonNull File file) {
        this(Arrays.asList(file));
    }

    /**
     * Equivalent to FileObserver(paths, FileObserver.ALL_EVENTS).
     *
     * @param files The files or directories to monitor
     */
    public FileObserver(@NonNull List<File> files) {
        this(files, ALL_EVENTS);
    }

    /**
@@ -159,11 +193,36 @@ public abstract class FileObserver {
     *
     * @param path The file or directory to monitor
     * @param mask The event or events (added together) to watch for
     *
     * @deprecated use {@link #FileObserver(File, int)} instead.
     */
    @Deprecated
    public FileObserver(String path, int mask) {
        m_path = path;
        m_mask = mask;
        m_descriptor = -1;
        this(new File(path), mask);
    }

    /**
     * Create a new file observer for a certain file or directory.
     * Monitoring does not start on creation!  You must call
     * {@link #startWatching()} before you will receive events.
     *
     * @param file The file or directory to monitor
     * @param mask The event or events (added together) to watch for
     */
    public FileObserver(@NonNull File file, int mask) {
        this(Arrays.asList(file), mask);
    }

    /**
     * Version of {@link #FileObserver(File, int)} that allows callers to monitor
     * multiple files or directories.
     *
     * @param files The files or directories to monitor
     * @param mask The event or events (added together) to watch for
     */
    public FileObserver(@NonNull List<File> files, int mask) {
        mFiles = files;
        mMask = mask;
    }

    protected void finalize() {
@@ -176,8 +235,8 @@ public abstract class FileObserver {
     * If monitoring is already started, this call has no effect.
     */
    public void startWatching() {
        if (m_descriptor < 0) {
            m_descriptor = s_observerThread.startWatching(m_path, m_mask, this);
        if (mDescriptors == null) {
            mDescriptors = s_observerThread.startWatching(mFiles, mMask, this);
        }
    }

@@ -187,9 +246,9 @@ public abstract class FileObserver {
     * monitoring is already stopped, this call has no effect.
     */
    public void stopWatching() {
        if (m_descriptor >= 0) {
            s_observerThread.stopWatching(m_descriptor);
            m_descriptor = -1;
        if (mDescriptors != null) {
            s_observerThread.stopWatching(mDescriptors);
            mDescriptors = null;
        }
    }

+27 −11
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@
*/

#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedPrimitiveArray.h>
#include <nativehelper/ScopedUtfChars.h>
#include "jni.h"
#include "utils/Log.h"
#include "utils/misc.h"
@@ -98,31 +100,45 @@ static void android_os_fileobserver_observe(JNIEnv* env, jobject object, jint fd
#endif
}

static jint android_os_fileobserver_startWatching(JNIEnv* env, jobject object, jint fd, jstring pathString, jint mask)
static void android_os_fileobserver_startWatching(JNIEnv* env, jobject object, jint fd,
                                                       jobjectArray pathStrings, jint mask,
                                                       jintArray wfdArray)
{
    int res = -1;
    ScopedIntArrayRW wfds(env, wfdArray);
    if (wfds.get() == nullptr) {
        jniThrowException(env, "java/lang/IllegalStateException", "Failed to get ScopedIntArrayRW");
    }

#if defined(__linux__)

    if (fd >= 0)
    {
        const char* path = env->GetStringUTFChars(pathString, NULL);
        size_t count = wfds.size();
        for (jsize i = 0; i < count; ++i) {
            jstring pathString = (jstring) env->GetObjectArrayElement(pathStrings, i);

        res = inotify_add_watch(fd, path, mask);
            ScopedUtfChars path(env, pathString);

        env->ReleaseStringUTFChars(pathString, path);
            wfds[i] = inotify_add_watch(fd, path.c_str(), mask);
        }
    }

#endif

    return res;
}

static void android_os_fileobserver_stopWatching(JNIEnv* env, jobject object, jint fd, jint wfd)
static void android_os_fileobserver_stopWatching(JNIEnv* env, jobject object,
                                                 jint fd, jintArray wfdArray)
{
#if defined(__linux__)

    inotify_rm_watch((int)fd, (uint32_t)wfd);
    ScopedIntArrayRO wfds(env, wfdArray);
    if (wfds.get() == nullptr) {
        jniThrowException(env, "java/lang/IllegalStateException", "Failed to get ScopedIntArrayRO");
    }
    size_t count = wfds.size();
    for (size_t i = 0; i < count; ++i) {
        inotify_rm_watch((int)fd, (uint32_t)wfds[i]);
    }

#endif
}
@@ -131,8 +147,8 @@ static const JNINativeMethod sMethods[] = {
     /* name, signature, funcPtr */
    { "init", "()I", (void*)android_os_fileobserver_init },
    { "observe", "(I)V", (void*)android_os_fileobserver_observe },
    { "startWatching", "(ILjava/lang/String;I)I", (void*)android_os_fileobserver_startWatching },
    { "stopWatching", "(II)V", (void*)android_os_fileobserver_stopWatching }
    { "startWatching", "(I[Ljava/lang/String;I[I)V", (void*)android_os_fileobserver_startWatching },
    { "stopWatching", "(I[I)V", (void*)android_os_fileobserver_stopWatching }

};