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 <nativehelper/JNIHelp.h> 19 #include "jni.h" 20 #include "utils/Log.h" 21 #include "utils/misc.h" 22 #include "core_jni_helpers.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 #if defined(__linux__) 33 #include <sys/inotify.h> 34 #endif 35 36 namespace android { 37 38 static jmethodID method_onEvent; 39 40 static jint android_os_fileobserver_init(JNIEnv* env, jobject object) 41 { 42 #if defined(__linux__) 43 return (jint)inotify_init(); 44 #else 45 return -1; 46 #endif 47 } 48 49 static void android_os_fileobserver_observe(JNIEnv* env, jobject object, jint fd) 50 { 51 #if defined(__linux__) 52 53 char event_buf[512]; 54 struct inotify_event* event; 55 56 while (1) 57 { 58 int event_pos = 0; 59 int num_bytes = read(fd, event_buf, sizeof(event_buf)); 60 61 if (num_bytes < (int)sizeof(*event)) 62 { 63 if (errno == EINTR) 64 continue; 65 66 ALOGE("***** ERROR! android_os_fileobserver_observe() got a short event!"); 67 return; 68 } 69 70 while (num_bytes >= (int)sizeof(*event)) 71 { 72 int event_size; 73 event = (struct inotify_event *)(event_buf + event_pos); 74 75 jstring path = NULL; 76 77 if (event->len > 0) 78 { 79 path = env->NewStringUTF(event->name); 80 } 81 82 env->CallVoidMethod(object, method_onEvent, event->wd, event->mask, path); 83 if (env->ExceptionCheck()) { 84 env->ExceptionDescribe(); 85 env->ExceptionClear(); 86 } 87 if (path != NULL) 88 { 89 env->DeleteLocalRef(path); 90 } 91 92 event_size = sizeof(*event) + event->len; 93 num_bytes -= event_size; 94 event_pos += event_size; 95 } 96 } 97 98 #endif 99 } 100 101 static jint android_os_fileobserver_startWatching(JNIEnv* env, jobject object, jint fd, jstring pathString, jint mask) 102 { 103 int res = -1; 104 105 #if defined(__linux__) 106 107 if (fd >= 0) 108 { 109 const char* path = env->GetStringUTFChars(pathString, NULL); 110 111 res = inotify_add_watch(fd, path, mask); 112 113 env->ReleaseStringUTFChars(pathString, path); 114 } 115 116 #endif 117 118 return res; 119 } 120 121 static void android_os_fileobserver_stopWatching(JNIEnv* env, jobject object, jint fd, jint wfd) 122 { 123 #if defined(__linux__) 124 125 inotify_rm_watch((int)fd, (uint32_t)wfd); 126 127 #endif 128 } 129 130 static const JNINativeMethod sMethods[] = { 131 /* name, signature, funcPtr */ 132 { "init", "()I", (void*)android_os_fileobserver_init }, 133 { "observe", "(I)V", (void*)android_os_fileobserver_observe }, 134 { "startWatching", "(ILjava/lang/String;I)I", (void*)android_os_fileobserver_startWatching }, 135 { "stopWatching", "(II)V", (void*)android_os_fileobserver_stopWatching } 136 137 }; 138 139 int register_android_os_FileObserver(JNIEnv* env) 140 { 141 jclass clazz = FindClassOrDie(env, "android/os/FileObserver$ObserverThread"); 142 143 method_onEvent = GetMethodIDOrDie(env, clazz, "onEvent", "(IILjava/lang/String;)V"); 144 145 return RegisterMethodsOrDie(env, "android/os/FileObserver$ObserverThread", sMethods, 146 NELEM(sMethods)); 147 } 148 149 } /* namespace android */ 150