1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "UEventObserver" 18 //#define LOG_NDEBUG 0 19 20 #include "utils/Log.h" 21 22 #include "hardware_legacy/uevent.h" 23 #include "jni.h" 24 #include "JNIHelp.h" 25 #include "android_runtime/AndroidRuntime.h" 26 27 #include <utils/Mutex.h> 28 #include <utils/Vector.h> 29 #include <utils/String8.h> 30 #include <ScopedUtfChars.h> 31 32 namespace android { 33 34 static Mutex gMatchesMutex; 35 static Vector<String8> gMatches; 36 37 static void nativeSetup(JNIEnv *env, jclass clazz) { 38 if (!uevent_init()) { 39 jniThrowException(env, "java/lang/RuntimeException", 40 "Unable to open socket for UEventObserver"); 41 } 42 } 43 44 static bool isMatch(const char* buffer, size_t length) { 45 AutoMutex _l(gMatchesMutex); 46 47 for (size_t i = 0; i < gMatches.size(); i++) { 48 const String8& match = gMatches.itemAt(i); 49 50 // Consider all zero-delimited fields of the buffer. 51 const char* field = buffer; 52 const char* end = buffer + length + 1; 53 do { 54 if (strstr(field, match.string())) { 55 ALOGV("Matched uevent message with pattern: %s", match.string()); 56 return true; 57 } 58 field += strlen(field) + 1; 59 } while (field != end); 60 } 61 return false; 62 } 63 64 static jstring nativeWaitForNextEvent(JNIEnv *env, jclass clazz) { 65 char buffer[1024]; 66 67 for (;;) { 68 int length = uevent_next_event(buffer, sizeof(buffer) - 1); 69 if (length <= 0) { 70 return NULL; 71 } 72 buffer[length] = '\0'; 73 74 ALOGV("Received uevent message: %s", buffer); 75 76 if (isMatch(buffer, length)) { 77 // Assume the message is ASCII. 78 jchar message[length]; 79 for (int i = 0; i < length; i++) { 80 message[i] = buffer[i]; 81 } 82 return env->NewString(message, length); 83 } 84 } 85 } 86 87 static void nativeAddMatch(JNIEnv* env, jclass clazz, jstring matchStr) { 88 ScopedUtfChars match(env, matchStr); 89 90 AutoMutex _l(gMatchesMutex); 91 gMatches.add(String8(match.c_str())); 92 } 93 94 static void nativeRemoveMatch(JNIEnv* env, jclass clazz, jstring matchStr) { 95 ScopedUtfChars match(env, matchStr); 96 97 AutoMutex _l(gMatchesMutex); 98 for (size_t i = 0; i < gMatches.size(); i++) { 99 if (gMatches.itemAt(i) == match.c_str()) { 100 gMatches.removeAt(i); 101 break; // only remove first occurrence 102 } 103 } 104 } 105 106 static JNINativeMethod gMethods[] = { 107 { "nativeSetup", "()V", 108 (void *)nativeSetup }, 109 { "nativeWaitForNextEvent", "()Ljava/lang/String;", 110 (void *)nativeWaitForNextEvent }, 111 { "nativeAddMatch", "(Ljava/lang/String;)V", 112 (void *)nativeAddMatch }, 113 { "nativeRemoveMatch", "(Ljava/lang/String;)V", 114 (void *)nativeRemoveMatch }, 115 }; 116 117 118 int register_android_os_UEventObserver(JNIEnv *env) 119 { 120 jclass clazz; 121 122 clazz = env->FindClass("android/os/UEventObserver"); 123 if (clazz == NULL) { 124 ALOGE("Can't find android/os/UEventObserver"); 125 return -1; 126 } 127 128 return AndroidRuntime::registerNativeMethods(env, 129 "android/os/UEventObserver", gMethods, NELEM(gMethods)); 130 } 131 132 } // namespace android 133