android_util_FileObserver.cpp revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
1/* //device/libs/android_runtime/android_util_FileObserver.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include "JNIHelp.h"
19#include "jni.h"
20#include "utils/Log.h"
21#include "utils/misc.h"
22#include "android_runtime/AndroidRuntime.h"
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <stdint.h>
28#include <fcntl.h>
29#include <sys/ioctl.h>
30#include <errno.h>
31
32#ifdef HAVE_INOTIFY
33#include <sys/inotify.h>
34#endif
35
36namespace android {
37
38static jmethodID method_onEvent;
39
40static jint android_os_fileobserver_init(JNIEnv* env, jobject object)
41{
42#ifdef HAVE_INOTIFY
43
44    return (jint)inotify_init();
45
46#else // HAVE_INOTIFY
47
48    return -1;
49
50#endif // HAVE_INOTIFY
51}
52
53static void android_os_fileobserver_observe(JNIEnv* env, jobject object, jint fd)
54{
55#ifdef HAVE_INOTIFY
56
57    char event_buf[512];
58    struct inotify_event* event;
59
60    while (1)
61    {
62        int event_pos = 0;
63        int num_bytes = read(fd, event_buf, sizeof(event_buf));
64
65        if (num_bytes < (int)sizeof(*event))
66        {
67            if (errno == EINTR)
68                continue;
69
70            LOGE("***** ERROR! android_os_fileobserver_observe() got a short event!");
71            return;
72        }
73
74    	while (num_bytes >= (int)sizeof(*event))
75    	{
76			int event_size;
77			event = (struct inotify_event *)(event_buf + event_pos);
78
79            jstring path = NULL;
80
81            if (event->len > 0)
82            {
83                path = env->NewStringUTF(event->name);
84            }
85
86		    env->CallVoidMethod(object, method_onEvent, event->wd, event->mask, path);
87
88		    event_size = sizeof(*event) + event->len;
89			num_bytes -= event_size;
90			event_pos += event_size;
91		}
92    }
93
94#endif // HAVE_INOTIFY
95}
96
97static jint android_os_fileobserver_startWatching(JNIEnv* env, jobject object, jint fd, jstring pathString, jint mask)
98{
99    int res = -1;
100
101#ifdef HAVE_INOTIFY
102
103    if (fd >= 0)
104    {
105        const char* path = env->GetStringUTFChars(pathString, NULL);
106
107        res = inotify_add_watch(fd, path, mask);
108
109        env->ReleaseStringUTFChars(pathString, path);
110    }
111
112#endif // HAVE_INOTIFY
113
114    return res;
115}
116
117static void android_os_fileobserver_stopWatching(JNIEnv* env, jobject object, jint fd, jint wfd)
118{
119#ifdef HAVE_INOTIFY
120
121    inotify_rm_watch((int)fd, (uint32_t)wfd);
122
123#endif // HAVE_INOTIFY
124}
125
126static JNINativeMethod sMethods[] = {
127     /* name, signature, funcPtr */
128    { "init", "()I", (void*)android_os_fileobserver_init },
129    { "observe", "(I)V", (void*)android_os_fileobserver_observe },
130    { "startWatching", "(ILjava/lang/String;I)I", (void*)android_os_fileobserver_startWatching },
131    { "stopWatching", "(II)V", (void*)android_os_fileobserver_stopWatching }
132
133};
134
135int register_android_os_FileObserver(JNIEnv* env)
136{
137    jclass clazz;
138
139    clazz = env->FindClass("android/os/FileObserver$ObserverThread");
140
141    if (clazz == NULL)
142	{
143        LOGE("Can't find android/os/FileObserver$ObserverThread");
144        return -1;
145    }
146
147    method_onEvent = env->GetMethodID(clazz, "onEvent", "(IILjava/lang/String;)V");
148    if (method_onEvent == NULL)
149    {
150        LOGE("Can't find FileObserver.onEvent(int, int, String)");
151        return -1;
152    }
153
154    return AndroidRuntime::registerNativeMethods(env, "android/os/FileObserver$ObserverThread", sMethods, NELEM(sMethods));
155}
156
157} /* namespace android */
158