C++程序  |  680行  |  18.72 KB

/*
 * Copyright 2016, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "wifi"

#include "jni.h"
#include <ScopedUtfChars.h>
#include <utils/misc.h>
#include <android_runtime/AndroidRuntime.h>
#include <utils/Log.h>
#include <utils/String16.h>

#include "wifi.h"
#include "wifi_hal.h"
#include "jni_helper.h"

namespace android {

/* JNI Helpers for wifi_hal implementation */

JNIHelper::JNIHelper(JavaVM *vm)
{
    vm->AttachCurrentThread(&mEnv, NULL);
    mVM = vm;
}

JNIHelper::JNIHelper(JNIEnv *env)
{
    mVM  = NULL;
    mEnv = env;
}

JNIHelper::~JNIHelper()
{
    if (mVM != NULL) {
        // mVM->DetachCurrentThread();  /* 'attempting to detach while still running code' */
        mVM = NULL;                     /* not really required; but may help debugging */
        mEnv = NULL;                    /* not really required; but may help debugging */
    }
}

jobject JNIHelper::newGlobalRef(jobject obj) {
    return mEnv->NewGlobalRef(obj);
}

void JNIHelper::deleteGlobalRef(jobject obj) {
    mEnv->DeleteGlobalRef(obj);
}

jobject JNIHelper::newLocalRef(jobject obj) {
    return mEnv->NewLocalRef(obj);
}

void JNIHelper::deleteLocalRef(jobject obj) {
    mEnv->DeleteLocalRef(obj);
}

void JNIHelper::throwException(const char *message, int line)
{
    ALOGE("error at line %d: %s", line, message);

    const char *className = "java/lang/Exception";

    jclass exClass = mEnv->FindClass(className );
    if ( exClass == NULL ) {
        ALOGE("Could not find exception class to throw error");
        ALOGE("error at line %d: %s", line, message);
        return;
    }

    mEnv->ThrowNew(exClass, message);
}

jboolean JNIHelper::getBoolField(jobject obj, const char *name)
{
    JNIObject<jclass> cls(*this, mEnv->GetObjectClass(obj));
    jfieldID field = mEnv->GetFieldID(cls, name, "Z");
    if (field == 0) {
        THROW(*this, "Error in accessing field");
        return 0;
    }

    return mEnv->GetBooleanField(obj, field);
}

jint JNIHelper::getIntField(jobject obj, const char *name)
{
    JNIObject<jclass> cls(*this, mEnv->GetObjectClass(obj));
    jfieldID field = mEnv->GetFieldID(cls, name, "I");
    if (field == 0) {
        THROW(*this, "Error in accessing field");
        return 0;
    }

    return mEnv->GetIntField(obj, field);
}

jbyte JNIHelper::getByteField(jobject obj, const char *name)
{
    JNIObject<jclass> cls(*this, mEnv->GetObjectClass(obj));
    jfieldID field = mEnv->GetFieldID(cls, name, "B");
    if (field == 0) {
        THROW(*this, "Error in accessing field");
        return 0;
    }

    return mEnv->GetByteField(obj, field);
}

jlong JNIHelper::getLongField(jobject obj, const char *name)
{
    JNIObject<jclass> cls(*this, mEnv->GetObjectClass(obj));
    jfieldID field = mEnv->GetFieldID(cls, name, "J");
    if (field == 0) {
        THROW(*this, "Error in accessing field");
        return 0;
    }

    return mEnv->GetLongField(obj, field);
}

JNIObject<jstring> JNIHelper::getStringField(jobject obj, const char *name)
{
    JNIObject<jobject> m = getObjectField(obj, name, "Ljava/lang/String;");
    if (m == NULL) {
        THROW(*this, "Error in accessing field");
        return JNIObject<jstring>(*this, NULL);
    }

    return JNIObject<jstring>(*this, (jstring)m.detach());
}

bool JNIHelper::getStringFieldValue(jobject obj, const char *name, char *buf, int size)
{
    JNIObject<jclass> cls(*this, mEnv->GetObjectClass(obj));
    jfieldID field = mEnv->GetFieldID(cls, name, "Ljava/lang/String;");
    if (field == 0) {
        THROW(*this, "Error in accessing field");
        return 0;
    }

    JNIObject<jobject> value(*this, mEnv->GetObjectField(obj, field));
    JNIObject<jstring> string(*this, (jstring)value.clone());
    ScopedUtfChars chars(mEnv, string);

    const char *utf = chars.c_str();
    if (utf == NULL) {
        THROW(*this, "Error in accessing value");
        return false;
    }

    if (*utf != 0 && size < 1) {
        return false;
    }

    strncpy(buf, utf, size);
    if (size > 0) {
        buf[size - 1] = 0;
    }

    return true;
}

jlong JNIHelper::getStaticLongField(jobject obj, const char *name)
{
    JNIObject<jclass> cls(*this, mEnv->GetObjectClass(obj));
    return getStaticLongField(cls, name);
}

jlong JNIHelper::getStaticLongField(jclass cls, const char *name)
{
    jfieldID field = mEnv->GetStaticFieldID(cls, name, "J");
    if (field == 0) {
        THROW(*this, "Error in accessing field");
        return 0;
    }
    //ALOGE("getStaticLongField %s %p", name, cls);
    return mEnv->GetStaticLongField(cls, field);
}

JNIObject<jobject> JNIHelper::getObjectField(jobject obj, const char *name, const char *type)
{
    JNIObject<jclass> cls(*this, mEnv->GetObjectClass(obj));
    jfieldID field = mEnv->GetFieldID(cls, name, type);
    if (field == 0) {
        THROW(*this, "Error in accessing field");
        return JNIObject<jobject>(*this, NULL);
    }

    return JNIObject<jobject>(*this, mEnv->GetObjectField(obj, field));
}

JNIObject<jobjectArray> JNIHelper::getArrayField(jobject obj, const char *name, const char *type)
{
    JNIObject<jclass> cls(*this, mEnv->GetObjectClass(obj));
    jfieldID field = mEnv->GetFieldID(cls, name, type);
    if (field == 0) {
        THROW(*this, "Error in accessing field");
        return JNIObject<jobjectArray>(*this, NULL);
    }

    return JNIObject<jobjectArray>(*this, (jobjectArray)mEnv->GetObjectField(obj, field));
}

jlong JNIHelper::getLongArrayField(jobject obj, const char *name, int index)
{
    JNIObject<jclass> cls(*this, mEnv->GetObjectClass(obj));
    jfieldID field = mEnv->GetFieldID(cls, name, "[J");
    if (field == 0) {
        THROW(*this, "Error in accessing field definition");
        return 0;
    }

    JNIObject<jlongArray> array(*this, (jlongArray)mEnv->GetObjectField(obj, field));
    if (array == NULL) {
        THROW(*this, "Error in accessing array");
        return 0;
    }

    jlong *elem = mEnv->GetLongArrayElements(array, 0);
    if (elem == NULL) {
        THROW(*this, "Error in accessing index element");
        return 0;
    }

    jlong value = elem[index];
    mEnv->ReleaseLongArrayElements(array, elem, 0);
    return value;
}

void JNIHelper::getByteArrayField(jobject obj, const char *name, byte* buf, int size) {
    JNIObject<jclass> cls(*this, mEnv->GetObjectClass(obj));
    jfieldID field = mEnv->GetFieldID(cls, name, "[B");
    if (field == 0) {
        THROW(*this, "Error in accessing field definition");
        return;
    }

    JNIObject<jbyteArray> array(*this, (jbyteArray)mEnv->GetObjectField(obj, field));
    if (array == NULL) {
        THROW(*this, "Error in accessing array");
        return;
    }

    jbyte *elem = mEnv->GetByteArrayElements(array, 0);
    if (elem == NULL) {
        THROW(*this, "Error in accessing index element");
        return;
    }

    memcpy(buf, elem, size);
    mEnv->ReleaseByteArrayElements(array, elem, 0);
}

jlong JNIHelper::getStaticLongArrayField(jobject obj, const char *name, int index)
{
    JNIObject<jclass> cls(*this, mEnv->GetObjectClass(obj));
    return getStaticLongArrayField(cls, name, index);
}

jlong JNIHelper::getStaticLongArrayField(jclass cls, const char *name, int index)
{
    jfieldID field = mEnv->GetStaticFieldID(cls, name, "[J");
    if (field == 0) {
        THROW(*this, "Error in accessing field definition");
        return 0;
    }

    JNIObject<jlongArray> array(*this, (jlongArray)mEnv->GetStaticObjectField(cls, field));
    jlong *elem = mEnv->GetLongArrayElements(array, 0);
    if (elem == NULL) {
        THROW(*this, "Error in accessing index element");
        return 0;
    }

    jlong value = elem[index];
    mEnv->ReleaseLongArrayElements(array, elem, 0);
    return value;
}

JNIObject<jobject> JNIHelper::getObjectArrayField(jobject obj, const char *name, const char *type,
int index)
{
    JNIObject<jclass> cls(*this, mEnv->GetObjectClass(obj));
    jfieldID field = mEnv->GetFieldID(cls, name, type);
    if (field == 0) {
        THROW(*this, "Error in accessing field definition");
        return JNIObject<jobject>(*this, NULL);
    }

    JNIObject<jobjectArray> array(*this, (jobjectArray)mEnv->GetObjectField(obj, field));
    JNIObject<jobject> elem(*this, mEnv->GetObjectArrayElement(array, index));
    if (elem.isNull()) {
        THROW(*this, "Error in accessing index element");
        return JNIObject<jobject>(*this, NULL);
    }
    return elem;
}

void JNIHelper::setIntField(jobject obj, const char *name, jint value)
{
    JNIObject<jclass> cls(*this, mEnv->GetObjectClass(obj));
    if (cls == NULL) {
        THROW(*this, "Error in accessing class");
        return;
    }

    jfieldID field = mEnv->GetFieldID(cls, name, "I");
    if (field == NULL) {
        THROW(*this, "Error in accessing field");
        return;
    }

    mEnv->SetIntField(obj, field, value);
}

void JNIHelper::setByteField(jobject obj, const char *name, jbyte value)
{
    JNIObject<jclass> cls(*this, mEnv->GetObjectClass(obj));
    if (cls == NULL) {
        THROW(*this, "Error in accessing class");
        return;
    }

    jfieldID field = mEnv->GetFieldID(cls, name, "B");
    if (field == NULL) {
        THROW(*this, "Error in accessing field");
        return;
    }

    mEnv->SetByteField(obj, field, value);
}

void JNIHelper::setBooleanField(jobject obj, const char *name, jboolean value)
{
    JNIObject<jclass> cls(*this, mEnv->GetObjectClass(obj));
    if (cls == NULL) {
        THROW(*this, "Error in accessing class");
        return;
    }

    jfieldID field = mEnv->GetFieldID(cls, name, "Z");
    if (field == NULL) {
        THROW(*this, "Error in accessing field");
        return;
    }

    mEnv->SetBooleanField(obj, field, value);
}

void JNIHelper::setLongField(jobject obj, const char *name, jlong value)
{
    JNIObject<jclass> cls(*this, mEnv->GetObjectClass(obj));
    if (cls == NULL) {
        THROW(*this, "Error in accessing class");
        return;
    }

    jfieldID field = mEnv->GetFieldID(cls, name, "J");
    if (field == NULL) {
        THROW(*this, "Error in accessing field");
        return;
    }

    mEnv->SetLongField(obj, field, value);
}

void JNIHelper::setStaticLongField(jobject obj, const char *name, jlong value)
{
    JNIObject<jclass> cls(*this, mEnv->GetObjectClass(obj));
    if (cls == NULL) {
        THROW(*this, "Error in accessing class");
        return;
    }

    setStaticLongField(cls, name, value);
}

void JNIHelper::setStaticLongField(jclass cls, const char *name, jlong value)
{
    jfieldID field = mEnv->GetStaticFieldID(cls, name, "J");
    if (field == NULL) {
        THROW(*this, "Error in accessing field");
        return;
    }

    mEnv->SetStaticLongField(cls, field, value);
}

void JNIHelper::setLongArrayField(jobject obj, const char *name, jlongArray value)
{
    JNIObject<jclass> cls(*this, mEnv->GetObjectClass(obj));
    if (cls == NULL) {
        THROW(*this, "Error in accessing field");
        return;
    }

    jfieldID field = mEnv->GetFieldID(cls, name, "[J");
    if (field == NULL) {
        THROW(*this, "Error in accessing field");
        return;
    }

    mEnv->SetObjectField(obj, field, value);
}

void JNIHelper::setStaticLongArrayField(jobject obj, const char *name, jlongArray value)
{
    JNIObject<jclass> cls(*this, mEnv->GetObjectClass(obj));
    if (cls == NULL) {
        THROW(*this, "Error in accessing field");
        return;
    }

    setStaticLongArrayField(cls, name, value);
}

void JNIHelper::setStaticLongArrayField(jclass cls, const char *name, jlongArray value)
{
    jfieldID field = mEnv->GetStaticFieldID(cls, name, "[J");
    if (field == NULL) {
        THROW(*this, "Error in accessing field");
        return;
    }

    mEnv->SetStaticObjectField(cls, field, value);
    ALOGD("array field set");
}

void JNIHelper::setLongArrayElement(jobject obj, const char *name, int index, jlong value)
{
    JNIObject<jclass> cls(*this, mEnv->GetObjectClass(obj));
    if (cls == NULL) {
        THROW(*this, "Error in accessing field");
        return;
    }

    jfieldID field = mEnv->GetFieldID(cls, name, "[J");
    if (field == NULL) {
        THROW(*this, "Error in accessing field");
        return;
    }

    JNIObject<jlongArray> array(*this, (jlongArray)mEnv->GetObjectField(obj, field));
    if (array == NULL) {
        THROW(*this, "Error in accessing array");
        return;
    }

    jlong *elem = mEnv->GetLongArrayElements(array, NULL);
    if (elem == NULL) {
        THROW(*this, "Error in accessing index element");
        return;
    }

    elem[index] = value;
    mEnv->ReleaseLongArrayElements(array, elem, 0);
}

void JNIHelper::setObjectField(jobject obj, const char *name, const char *type, jobject value)
{
    JNIObject<jclass> cls(*this, mEnv->GetObjectClass(obj));
    if (cls == NULL) {
        THROW(*this, "Error in accessing class");
        return;
    }

    jfieldID field = mEnv->GetFieldID(cls, name, type);
    if (field == NULL) {
        THROW(*this, "Error in accessing field");
        return;
    }

    mEnv->SetObjectField(obj, field, value);
}

jboolean JNIHelper::setStringField(jobject obj, const char *name, const char *value)
{
    JNIObject<jstring> str(*this, mEnv->NewStringUTF(value));

    if (mEnv->ExceptionCheck()) {
        mEnv->ExceptionDescribe();
        mEnv->ExceptionClear();
        return false;
    }

    if (str == NULL) {
        THROW(*this, "Error creating string");
        return false;
    }

    setObjectField(obj, name, "Ljava/lang/String;", str);
    return true;
}

void JNIHelper::reportEvent(jclass cls, const char *method, const char *signature, ...)
{
    va_list params;
    va_start(params, signature);

    jmethodID methodID = mEnv->GetStaticMethodID(cls, method, signature);
    if (methodID == 0) {
        ALOGE("Error in getting method ID");
        return;
    }

    mEnv->CallStaticVoidMethodV(cls, methodID, params);
    if (mEnv->ExceptionCheck()) {
        mEnv->ExceptionDescribe();
        mEnv->ExceptionClear();
    }

    va_end(params);
}

void JNIHelper::callMethod(jobject obj, const char *method, const char *signature, ...)
{
    va_list params;
    va_start(params, signature);

    jclass cls = mEnv->GetObjectClass(obj);
    jmethodID methodID = mEnv->GetMethodID(cls, method, signature);
    if (methodID == 0) {
        ALOGE("Error in getting method ID");
        return;
    }

    mEnv->CallVoidMethodV(obj, methodID, params);
    if (mEnv->ExceptionCheck()) {
        mEnv->ExceptionDescribe();
        mEnv->ExceptionClear();
    }

    va_end(params);
}

jboolean JNIHelper::callStaticMethod(jclass cls, const char *method, const char *signature, ...)
{
    va_list params;
    va_start(params, signature);

    jmethodID methodID = mEnv->GetStaticMethodID(cls, method, signature);
    if (methodID == 0) {
        ALOGE("Error in getting method ID");
        return false;
    }

    jboolean result = mEnv->CallStaticBooleanMethodV(cls, methodID, params);
    if (mEnv->ExceptionCheck()) {
        mEnv->ExceptionDescribe();
        mEnv->ExceptionClear();
        return false;
    }

    va_end(params);
    return result;
}

JNIObject<jobject> JNIHelper::createObject(const char *className) {
    return createObjectWithArgs(className, "()V");
}

JNIObject<jobject> JNIHelper::createObjectWithArgs(
    const char *className, const char *signature, ...)
{
    va_list params;
    va_start(params, signature);

    JNIObject<jclass> cls(*this, mEnv->FindClass(className));
    if (cls == NULL) {
        ALOGE("Error in finding class %s", className);
        return JNIObject<jobject>(*this, NULL);
    }

    jmethodID constructor = mEnv->GetMethodID(cls, "<init>", signature);
    if (constructor == 0) {
        ALOGE("Error in constructor ID for %s", className);
        return JNIObject<jobject>(*this, NULL);
    }

    JNIObject<jobject> obj(*this, mEnv->NewObjectV(cls, constructor, params));
    if (obj == NULL) {
        ALOGE("Could not create new object of %s", className);
        return JNIObject<jobject>(*this, NULL);
    }

    va_end(params);
    return obj;
}

JNIObject<jobjectArray> JNIHelper::createObjectArray(const char *className, int num)
{
    JNIObject<jclass> cls(*this, mEnv->FindClass(className));
    if (cls == NULL) {
        ALOGE("Error in finding class %s", className);
        return JNIObject<jobjectArray>(*this, NULL);
    }

    JNIObject<jobject> array(*this, mEnv->NewObjectArray(num, cls.get(), NULL));
    if (array.get() == NULL) {
        ALOGE("Error in creating array of class %s", className);
        return JNIObject<jobjectArray>(*this, NULL);
    }

    return JNIObject<jobjectArray>(*this, (jobjectArray)array.detach());
}

JNIObject<jobject> JNIHelper::getObjectArrayElement(jobjectArray array, int index)
{
    return JNIObject<jobject>(*this, mEnv->GetObjectArrayElement(array, index));
}

JNIObject<jobject> JNIHelper::getObjectArrayElement(jobject array, int index)
{
    return getObjectArrayElement((jobjectArray)array, index);
}

int JNIHelper::getArrayLength(jarray array) {
    return mEnv->GetArrayLength(array);
}

JNIObject<jobjectArray> JNIHelper::newObjectArray(int num, const char *className, jobject val) {
    JNIObject<jclass> cls(*this, mEnv->FindClass(className));
    if (cls == NULL) {
        ALOGE("Error in finding class %s", className);
        return JNIObject<jobjectArray>(*this, NULL);
    }

    return JNIObject<jobjectArray>(*this, mEnv->NewObjectArray(num, cls, val));
}

JNIObject<jbyteArray> JNIHelper::newByteArray(int num) {
    return JNIObject<jbyteArray>(*this, mEnv->NewByteArray(num));
}

JNIObject<jintArray> JNIHelper::newIntArray(int num) {
    return JNIObject<jintArray>(*this, mEnv->NewIntArray(num));
}

JNIObject<jlongArray> JNIHelper::newLongArray(int num) {
    return JNIObject<jlongArray>(*this, mEnv->NewLongArray(num));
}

JNIObject<jstring> JNIHelper::newStringUTF(const char *utf) {
    return JNIObject<jstring>(*this, mEnv->NewStringUTF(utf));
}

void JNIHelper::setObjectArrayElement(jobjectArray array, int index, jobject obj) {
    mEnv->SetObjectArrayElement(array, index, obj);
}

void JNIHelper::setByteArrayRegion(jbyteArray array, int from, int to, const jbyte *bytes) {
    mEnv->SetByteArrayRegion(array, from, to, bytes);
}

void JNIHelper::setIntArrayRegion(jintArray array, int from, int to, const jint *ints) {
    mEnv->SetIntArrayRegion(array, from, to, ints);
}

void JNIHelper::setLongArrayRegion(jlongArray array, int from, int to, const jlong *longs) {
    mEnv->SetLongArrayRegion(array, from, to, longs);
}

}; // namespace android