summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Sudheer Shanka <sudheersai@google.com> 2019-01-28 16:01:50 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2019-01-28 16:01:50 +0000
commit31f977a44344b8930143f16ab7f2fee4c5302d33 (patch)
treedee7b5715ea330cc40b75ad5b67996c534fba819
parent175e2f24a2f052a92197185360383494a7886f8d (diff)
parentf7c79b4f06fef85879dd6adfd4062ce0132664ca (diff)
Merge "Update FileObserver to be able to watch multiple files."
-rw-r--r--api/current.txt8
-rw-r--r--core/java/android/os/FileObserver.java107
-rw-r--r--core/jni/android_util_FileObserver.cpp38
3 files changed, 116 insertions, 37 deletions
diff --git a/api/current.txt b/api/current.txt
index 0544b27bb903..361ee74becdd 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -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();
diff --git a/core/java/android/os/FileObserver.java b/core/java/android/os/FileObserver.java
index dd85e1584f0e..da0389578e15 100644
--- a/core/java/android/os/FileObserver.java
+++ b/core/java/android/os/FileObserver.java
@@ -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);
+
+ startWatching(m_fd, paths, mask, wfds);
- Integer i = new Integer(wfd);
- if (wfd >= 0) {
- synchronized (m_observers) {
- m_observers.put(i, new WeakReference(observer));
+ final WeakReference<FileObserver> fileObserverWeakReference =
+ new WeakReference<>(observer);
+ synchronized (m_observers) {
+ 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;
}
}
diff --git a/core/jni/android_util_FileObserver.cpp b/core/jni/android_util_FileObserver.cpp
index 6f975b23e5bd..d25192a57228 100644
--- a/core/jni/android_util_FileObserver.cpp
+++ b/core/jni/android_util_FileObserver.cpp
@@ -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 }
};