Home | History | Annotate | Download | only in jni
      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 
     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 
     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 
    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 
    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 
    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