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