19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOG_TAG "UEventObserver"
189cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown//#define LOG_NDEBUG 0
199cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "utils/Log.h"
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "hardware_legacy/uevent.h"
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "jni.h"
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "JNIHelp.h"
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "android_runtime/AndroidRuntime.h"
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
279cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown#include <utils/Mutex.h>
289cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown#include <utils/Vector.h>
299cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown#include <utils/String8.h>
309cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown#include <ScopedUtfChars.h>
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
329cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brownnamespace android {
339cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown
349cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brownstatic Mutex gMatchesMutex;
359cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brownstatic Vector<String8> gMatches;
369cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown
379cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brownstatic void nativeSetup(JNIEnv *env, jclass clazz) {
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!uevent_init()) {
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jniThrowException(env, "java/lang/RuntimeException",
409cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown                "Unable to open socket for UEventObserver");
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
449cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brownstatic bool isMatch(const char* buffer, size_t length) {
459cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown    AutoMutex _l(gMatchesMutex);
469cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown
479cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown    for (size_t i = 0; i < gMatches.size(); i++) {
489cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown        const String8& match = gMatches.itemAt(i);
499cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown
509cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown        // Consider all zero-delimited fields of the buffer.
519cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown        const char* field = buffer;
52c51cb89dd64cf366c162cf0fed4ba893f5c3e985Jeff Brown        const char* end = buffer + length + 1;
539cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown        do {
549cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown            if (strstr(field, match.string())) {
559cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown                ALOGV("Matched uevent message with pattern: %s", match.string());
569cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown                return true;
579cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown            }
589cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown            field += strlen(field) + 1;
599cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown        } while (field != end);
609cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown    }
619cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown    return false;
629cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown}
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
649cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brownstatic jstring nativeWaitForNextEvent(JNIEnv *env, jclass clazz) {
659cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown    char buffer[1024];
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
679cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown    for (;;) {
689cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown        int length = uevent_next_event(buffer, sizeof(buffer) - 1);
699cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown        if (length <= 0) {
709cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown            return NULL;
719cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown        }
729cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown        buffer[length] = '\0';
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
749cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown        ALOGV("Received uevent message: %s", buffer);
759cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown
769cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown        if (isMatch(buffer, length)) {
779cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown            // Assume the message is ASCII.
789cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown            jchar message[length];
799cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown            for (int i = 0; i < length; i++) {
809cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown                message[i] = buffer[i];
819cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown            }
829cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown            return env->NewString(message, length);
839cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown        }
849cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown    }
859cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown}
869cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown
879cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brownstatic void nativeAddMatch(JNIEnv* env, jclass clazz, jstring matchStr) {
889cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown    ScopedUtfChars match(env, matchStr);
899cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown
909cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown    AutoMutex _l(gMatchesMutex);
919cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown    gMatches.add(String8(match.c_str()));
929cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown}
939cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown
949cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brownstatic void nativeRemoveMatch(JNIEnv* env, jclass clazz, jstring matchStr) {
959cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown    ScopedUtfChars match(env, matchStr);
969cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown
979cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown    AutoMutex _l(gMatchesMutex);
989cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown    for (size_t i = 0; i < gMatches.size(); i++) {
999cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown        if (gMatches.itemAt(i) == match.c_str()) {
1009cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown            gMatches.removeAt(i);
1019cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown            break; // only remove first occurrence
1029cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown        }
1039cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown    }
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic JNINativeMethod gMethods[] = {
1079cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown    { "nativeSetup", "()V",
1089cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown            (void *)nativeSetup },
1099cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown    { "nativeWaitForNextEvent", "()Ljava/lang/String;",
1109cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown            (void *)nativeWaitForNextEvent },
1119cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown    { "nativeAddMatch", "(Ljava/lang/String;)V",
1129cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown            (void *)nativeAddMatch },
1139cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown    { "nativeRemoveMatch", "(Ljava/lang/String;)V",
1149cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown            (void *)nativeRemoveMatch },
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint register_android_os_UEventObserver(JNIEnv *env)
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    jclass clazz;
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    clazz = env->FindClass("android/os/UEventObserver");
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (clazz == NULL) {
1243762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Can't find android/os/UEventObserver");
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return AndroidRuntime::registerNativeMethods(env,
1299cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown            "android/os/UEventObserver", gMethods, NELEM(gMethods));
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}   // namespace android
133