• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
36 namespace android {
37 
38 static jmethodID method_onEvent;
39 
android_os_fileobserver_init(JNIEnv * env,jobject object)40 static 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 
android_os_fileobserver_observe(JNIEnv * env,jobject object,jint fd)53 static 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             ALOGE("***** 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             if (env->ExceptionCheck()) {
88                 env->ExceptionDescribe();
89                 env->ExceptionClear();
90             }
91             if (path != NULL)
92             {
93                 env->DeleteLocalRef(path);
94             }
95 
96             event_size = sizeof(*event) + event->len;
97             num_bytes -= event_size;
98             event_pos += event_size;
99         }
100     }
101 
102 #endif // HAVE_INOTIFY
103 }
104 
android_os_fileobserver_startWatching(JNIEnv * env,jobject object,jint fd,jstring pathString,jint mask)105 static jint android_os_fileobserver_startWatching(JNIEnv* env, jobject object, jint fd, jstring pathString, jint mask)
106 {
107     int res = -1;
108 
109 #ifdef HAVE_INOTIFY
110 
111     if (fd >= 0)
112     {
113         const char* path = env->GetStringUTFChars(pathString, NULL);
114 
115         res = inotify_add_watch(fd, path, mask);
116 
117         env->ReleaseStringUTFChars(pathString, path);
118     }
119 
120 #endif // HAVE_INOTIFY
121 
122     return res;
123 }
124 
android_os_fileobserver_stopWatching(JNIEnv * env,jobject object,jint fd,jint wfd)125 static void android_os_fileobserver_stopWatching(JNIEnv* env, jobject object, jint fd, jint wfd)
126 {
127 #ifdef HAVE_INOTIFY
128 
129     inotify_rm_watch((int)fd, (uint32_t)wfd);
130 
131 #endif // HAVE_INOTIFY
132 }
133 
134 static JNINativeMethod sMethods[] = {
135      /* name, signature, funcPtr */
136     { "init", "()I", (void*)android_os_fileobserver_init },
137     { "observe", "(I)V", (void*)android_os_fileobserver_observe },
138     { "startWatching", "(ILjava/lang/String;I)I", (void*)android_os_fileobserver_startWatching },
139     { "stopWatching", "(II)V", (void*)android_os_fileobserver_stopWatching }
140 
141 };
142 
register_android_os_FileObserver(JNIEnv * env)143 int register_android_os_FileObserver(JNIEnv* env)
144 {
145     jclass clazz;
146 
147     clazz = env->FindClass("android/os/FileObserver$ObserverThread");
148 
149     if (clazz == NULL)
150 	{
151         ALOGE("Can't find android/os/FileObserver$ObserverThread");
152         return -1;
153     }
154 
155     method_onEvent = env->GetMethodID(clazz, "onEvent", "(IILjava/lang/String;)V");
156     if (method_onEvent == NULL)
157     {
158         ALOGE("Can't find FileObserver.onEvent(int, int, String)");
159         return -1;
160     }
161 
162     return AndroidRuntime::registerNativeMethods(env, "android/os/FileObserver$ObserverThread", sMethods, NELEM(sMethods));
163 }
164 
165 } /* namespace android */
166