blob: c64c21244fe0469512ee16cfe0a8e0cc6e8fe571 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/* //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
Steven Moreland2279b252017-07-19 09:50:45 -070018#include <nativehelper/JNIHelp.h>
Sudheer Shankaf7c79b42019-01-27 14:18:26 -080019#include <nativehelper/ScopedPrimitiveArray.h>
20#include <nativehelper/ScopedUtfChars.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021#include "jni.h"
22#include "utils/Log.h"
23#include "utils/misc.h"
Andreas Gampeed6b9df2014-11-20 22:02:20 -080024#include "core_jni_helpers.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <stdint.h>
30#include <fcntl.h>
31#include <sys/ioctl.h>
32#include <errno.h>
33
Yabin Cui20a9cf42014-11-10 15:43:18 -080034#if defined(__linux__)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035#include <sys/inotify.h>
36#endif
37
38namespace android {
39
40static jmethodID method_onEvent;
41
42static jint android_os_fileobserver_init(JNIEnv* env, jobject object)
43{
Yabin Cui20a9cf42014-11-10 15:43:18 -080044#if defined(__linux__)
Nick Kralevich4b3a08c2019-01-28 10:39:10 -080045 return (jint)inotify_init1(IN_CLOEXEC);
Yabin Cui20a9cf42014-11-10 15:43:18 -080046#else
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047 return -1;
Yabin Cui20a9cf42014-11-10 15:43:18 -080048#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049}
50
51static void android_os_fileobserver_observe(JNIEnv* env, jobject object, jint fd)
52{
Yabin Cui20a9cf42014-11-10 15:43:18 -080053#if defined(__linux__)
54
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055 char event_buf[512];
56 struct inotify_event* event;
Yabin Cui20a9cf42014-11-10 15:43:18 -080057
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058 while (1)
59 {
60 int event_pos = 0;
61 int num_bytes = read(fd, event_buf, sizeof(event_buf));
Yabin Cui20a9cf42014-11-10 15:43:18 -080062
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063 if (num_bytes < (int)sizeof(*event))
64 {
65 if (errno == EINTR)
66 continue;
67
Steve Block3762c312012-01-06 19:20:56 +000068 ALOGE("***** ERROR! android_os_fileobserver_observe() got a short event!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069 return;
70 }
Yabin Cui20a9cf42014-11-10 15:43:18 -080071
Mike Lockwood59d25d02010-02-18 07:01:28 -050072 while (num_bytes >= (int)sizeof(*event))
73 {
74 int event_size;
75 event = (struct inotify_event *)(event_buf + event_pos);
76
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077 jstring path = NULL;
Yabin Cui20a9cf42014-11-10 15:43:18 -080078
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 if (event->len > 0)
80 {
81 path = env->NewStringUTF(event->name);
82 }
Mike Lockwood59d25d02010-02-18 07:01:28 -050083
84 env->CallVoidMethod(object, method_onEvent, event->wd, event->mask, path);
85 if (env->ExceptionCheck()) {
86 env->ExceptionDescribe();
87 env->ExceptionClear();
88 }
The Android Open Source Projectb22d55b2009-03-05 15:45:10 -080089 if (path != NULL)
90 {
91 env->DeleteLocalRef(path);
92 }
Mike Lockwood59d25d02010-02-18 07:01:28 -050093
94 event_size = sizeof(*event) + event->len;
95 num_bytes -= event_size;
96 event_pos += event_size;
97 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 }
Yabin Cui20a9cf42014-11-10 15:43:18 -080099
100#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101}
102
Sudheer Shankaf7c79b42019-01-27 14:18:26 -0800103static void android_os_fileobserver_startWatching(JNIEnv* env, jobject object, jint fd,
104 jobjectArray pathStrings, jint mask,
105 jintArray wfdArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106{
Sudheer Shankaf7c79b42019-01-27 14:18:26 -0800107 ScopedIntArrayRW wfds(env, wfdArray);
108 if (wfds.get() == nullptr) {
109 jniThrowException(env, "java/lang/IllegalStateException", "Failed to get ScopedIntArrayRW");
110 }
Yabin Cui20a9cf42014-11-10 15:43:18 -0800111
112#if defined(__linux__)
113
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114 if (fd >= 0)
115 {
Sudheer Shankaf7c79b42019-01-27 14:18:26 -0800116 size_t count = wfds.size();
117 for (jsize i = 0; i < count; ++i) {
118 jstring pathString = (jstring) env->GetObjectArrayElement(pathStrings, i);
Yabin Cui20a9cf42014-11-10 15:43:18 -0800119
Sudheer Shankaf7c79b42019-01-27 14:18:26 -0800120 ScopedUtfChars path(env, pathString);
Yabin Cui20a9cf42014-11-10 15:43:18 -0800121
Sudheer Shankaf7c79b42019-01-27 14:18:26 -0800122 wfds[i] = inotify_add_watch(fd, path.c_str(), mask);
123 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 }
125
Yabin Cui20a9cf42014-11-10 15:43:18 -0800126#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127}
128
Sudheer Shankaf7c79b42019-01-27 14:18:26 -0800129static void android_os_fileobserver_stopWatching(JNIEnv* env, jobject object,
130 jint fd, jintArray wfdArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131{
Yabin Cui20a9cf42014-11-10 15:43:18 -0800132#if defined(__linux__)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133
Sudheer Shankaf7c79b42019-01-27 14:18:26 -0800134 ScopedIntArrayRO wfds(env, wfdArray);
135 if (wfds.get() == nullptr) {
136 jniThrowException(env, "java/lang/IllegalStateException", "Failed to get ScopedIntArrayRO");
137 }
138 size_t count = wfds.size();
139 for (size_t i = 0; i < count; ++i) {
140 inotify_rm_watch((int)fd, (uint32_t)wfds[i]);
141 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142
Yabin Cui20a9cf42014-11-10 15:43:18 -0800143#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144}
145
Daniel Micay76f6a862015-09-19 17:31:01 -0400146static const JNINativeMethod sMethods[] = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 /* name, signature, funcPtr */
148 { "init", "()I", (void*)android_os_fileobserver_init },
149 { "observe", "(I)V", (void*)android_os_fileobserver_observe },
Sudheer Shankaf7c79b42019-01-27 14:18:26 -0800150 { "startWatching", "(I[Ljava/lang/String;I[I)V", (void*)android_os_fileobserver_startWatching },
151 { "stopWatching", "(I[I)V", (void*)android_os_fileobserver_stopWatching }
Yabin Cui20a9cf42014-11-10 15:43:18 -0800152
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153};
154
155int register_android_os_FileObserver(JNIEnv* env)
156{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800157 jclass clazz = FindClassOrDie(env, "android/os/FileObserver$ObserverThread");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800159 method_onEvent = GetMethodIDOrDie(env, clazz, "onEvent", "(IILjava/lang/String;)V");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800161 return RegisterMethodsOrDie(env, "android/os/FileObserver$ObserverThread", sMethods,
162 NELEM(sMethods));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163}
164
165} /* namespace android */