More HAL functionality
This change implements JNI plugs for delivering events to
WifiNative in framework. Also introduces a test utility.
Also has updated Gscan.h which is made up-to-date with the
promised functionatliy.
Change-Id: I12dd6d9f171e01e4b23ce4839b4022acd5e599cb
Conflicts:
service/Android.mk
diff --git a/service/jni/com_android_server_wifi_WifiNative.cpp b/service/jni/com_android_server_wifi_WifiNative.cpp
index 1fb2abb..638044e 100644
--- a/service/jni/com_android_server_wifi_WifiNative.cpp
+++ b/service/jni/com_android_server_wifi_WifiNative.cpp
@@ -25,6 +25,7 @@
#include "wifi.h"
#include "wifi_hal.h"
+#include "jni_helper.h"
#define REPLY_BUF_SIZE 4096 // wpa_supplicant's maximum size.
#define EVENT_BUF_SIZE 2048
@@ -141,32 +142,202 @@
return doStringCommand(env,javaCommand);
}
-static wifi_handle halHandle;
-static jboolean android_net_wifi_startHal(JNIEnv* env, jobject) {
+/* wifi_hal <==> WifiNative bridge */
+
+static jobject mObj; /* saved WifiNative object */
+static JavaVM *mVM; /* saved JVM pointer */
+
+static const char *WifiHandleVarName = "mWifiHalHandle";
+static const char *WifiIfaceHandleVarName = "mWifiIfaceHandles";
+static jmethodID OnScanResultsMethodID;
+
+static JNIEnv *getEnv() {
+ JNIEnv *env = NULL;
+ mVM->AttachCurrentThread(&env, NULL);
+ return env;
+}
+
+static wifi_handle getWifiHandle(JNIEnv *env, jobject obj) {
+ return (wifi_handle) getLongField(env, obj, WifiHandleVarName);
+}
+
+static wifi_interface_handle getIfaceHandle(JNIEnv *env, jobject obj, jint index) {
+ return (wifi_interface_handle) getLongArrayField(env, obj, WifiIfaceHandleVarName, index);
+}
+
+static void saveEventMethodIds(JNIEnv *env, jobject obj) {
+
+ jclass cls = (env)->GetObjectClass(obj);
+ if (cls == NULL) {
+ ALOGE("Error in accessing class");
+ return;
+ } else {
+ ALOGD("cls = %p", cls);
+ }
+
+ jmethodID method = env->GetMethodID(cls, "onScanResults",
+ "(I[Lcom/android/server/wifi/WifiNative$ScanResult;)V");
+
+ if (method == NULL) {
+ ALOGE("Error in getting method ID");
+ return;
+ } else {
+ ALOGD("method = %p", method);
+ }
+}
+
+static jboolean android_net_wifi_startHal(JNIEnv* env, jobject obj) {
ALOGD("In wifi start Hal");
+ wifi_handle halHandle = getWifiHandle(env, obj);
if (halHandle == NULL) {
wifi_error res = wifi_initialize(&halHandle);
+ if (res == WIFI_SUCCESS) {
+ setLongField(env, obj, WifiHandleVarName, (jlong)halHandle);
+ }
+ env->GetJavaVM(&mVM);
+ mObj = env->NewGlobalRef(obj);
+ ALOGD("halHandle = %p, mVM = %p, mObj = %p", halHandle, mVM, mObj);
return res == WIFI_SUCCESS;
+ } else {
+ return true;
}
- else
- return false;
}
void android_net_wifi_hal_cleaned_up_handler(wifi_handle handle) {
ALOGD("In wifi cleaned up handler");
- halHandle = NULL;
+
+ JNIEnv * env = getEnv();
+ setLongField(env, mObj, WifiHandleVarName, 0);
+ env->DeleteGlobalRef(mObj);
+ mObj = NULL;
+ mVM = NULL;
}
-static void android_net_wifi_stopHal(JNIEnv* env, jobject) {
+static void android_net_wifi_stopHal(JNIEnv* env, jobject obj) {
ALOGD("In wifi stop Hal");
+ wifi_handle halHandle = getWifiHandle(env, obj);
wifi_cleanup(halHandle, android_net_wifi_hal_cleaned_up_handler);
}
-static void android_net_wifi_waitForHalEvents(JNIEnv* env, jobject) {
- ALOGD("In wifi waitForHalEvents");
+static void android_net_wifi_waitForHalEvents(JNIEnv* env, jobject obj) {
+
+ ALOGD("waitForHalEvents called, vm = %p, obj = %p, env = %p", mVM, mObj, env);
+
+ wifi_handle halHandle = getWifiHandle(env, obj);
+ ALOGD("halHandle = %p", halHandle);
wifi_event_loop(halHandle);
}
+static int android_net_wifi_getInterfaces(JNIEnv *env, jobject obj) {
+ int n = 0;
+ wifi_handle halHandle = getWifiHandle(env, obj);
+ wifi_interface_handle *ifaceHandles = NULL;
+ int result = wifi_get_ifaces(halHandle, &n, &ifaceHandles);
+ if (result < 0) {
+ return result;
+ }
+
+ jlongArray array = (env)->NewLongArray(n);
+ if (array == NULL) {
+ THROW(env, "Error in accessing array");
+ return 0;
+ }
+
+ jlong elems[8];
+ if (n > 8) {
+ THROW(env, "Too many interfaces");
+ return 0;
+ }
+
+ for (int i = 0; i < n; i++) {
+ elems[i] = reinterpret_cast<jlong>(ifaceHandles[i]);
+ }
+
+ env->SetLongArrayRegion(array, 0, n, elems);
+
+ setLongArrayField(env, obj, WifiIfaceHandleVarName, array);
+ return (result < 0) ? result : n;
+}
+
+static jstring android_net_wifi_getInterfaceName(JNIEnv *env, jobject obj, jint i) {
+ char buf[EVENT_BUF_SIZE];
+
+ jlong value = getLongArrayField(env, obj, WifiIfaceHandleVarName, i);
+ wifi_interface_handle handle = (wifi_interface_handle) value;
+ int result = ::wifi_get_iface_name(handle, buf, sizeof(buf));
+ if (result < 0) {
+ return NULL;
+ } else {
+ return env->NewStringUTF(buf);
+ }
+}
+
+static void onScanResults(wifi_request_id id, unsigned num_results, wifi_scan_result *results) {
+ JNIEnv *env = NULL;
+ mVM->AttachCurrentThread(&env, NULL);
+
+ ALOGD("onScanResults called, vm = %p, obj = %p, env = %p", mVM, mObj, env);
+
+ jclass clsScanResult = (env)->FindClass("com/android/server/wifi/WifiNative$ScanResult");
+ if (clsScanResult == NULL) {
+ ALOGE("Error in accessing class");
+ return;
+ }
+
+ jobjectArray scanResults = env->NewObjectArray(num_results, clsScanResult, NULL);
+ if (scanResults == NULL) {
+ ALOGE("Error in allocating array");
+ return;
+ }
+
+ for (unsigned i = 0; i < num_results; i++) {
+
+ jobject scanResult = createObject(env, "com/android/server/wifi/WifiNative$ScanResult");
+ if (scanResult == NULL) {
+ ALOGE("Error in creating scan result");
+ return;
+ }
+
+ setStringField(env, scanResult, "SSID", results[i].ssid);
+
+ char bssid[32];
+ sprintf(bssid, "%0x:%0x:%0x:%0x:%0x:%0x", results[i].bssid[0], results[i].bssid[1],
+ results[i].bssid[2], results[i].bssid[3], results[i].bssid[4], results[i].bssid[5]);
+
+ setStringField(env, scanResult, "BSSID", bssid);
+
+ setIntField(env, scanResult, "level", results[i].rssi);
+ setLongField(env, scanResult, "timestamp", results[i].ts);
+ setIntField(env, scanResult, "frequency", results[i].channel);
+
+ env->SetObjectArrayElement(scanResults, i, scanResult);
+ }
+
+ reportEvent(env, mObj, "onScanResults",
+ "(I[Lcom/android/server/wifi/WifiNative$ScanResult;)V", id, scanResults);
+}
+
+static jboolean android_net_wifi_startScan(JNIEnv *env, jobject obj, jint iface, jint id) {
+
+ wifi_interface_handle handle = getIfaceHandle(env, obj, iface);
+ ALOGD("starting scan on interface[%d] = %p", iface, handle);
+
+ wifi_scan_cmd_params params;
+ memset(¶ms, 0, sizeof(params));
+
+ wifi_scan_result_handler handler;
+ memset(&handler, 0, sizeof(handler));
+ handler.on_scan_results = &onScanResults;
+
+ return wifi_start_gscan(id, handle, params, handler) == WIFI_SUCCESS;
+}
+
+static jboolean android_net_wifi_stopScan(JNIEnv *env, jobject obj, jint iface, jint id) {
+ wifi_interface_handle handle = getIfaceHandle(env, obj, iface);
+ ALOGD("stopping scan on interface[%d] = %p", iface, handle);
+
+ return wifi_stop_gscan(id, handle);
+}
// ----------------------------------------------------------------------------
@@ -192,6 +363,10 @@
{ "startHalNative", "()Z", (void*) android_net_wifi_startHal },
{ "stopHalNative", "()V", (void*) android_net_wifi_stopHal },
{ "waitForHalEventNative", "()V", (void*) android_net_wifi_waitForHalEvents },
+ { "getInterfacesNative", "()I", (void*) android_net_wifi_getInterfaces},
+ { "getInterfaceNameNative", "(I)Ljava/lang/String;", (void*) android_net_wifi_getInterfaceName},
+ { "startScanNative", "(II)Z", (void*) android_net_wifi_startScan},
+ { "stopScanNative", "(II)Z", (void*) android_net_wifi_stopScan}
};
int register_android_net_wifi_WifiNative(JNIEnv* env) {
@@ -208,4 +383,3 @@
}
}; // namespace android
-
diff --git a/service/jni/jni_helper.cpp b/service/jni/jni_helper.cpp
new file mode 100644
index 0000000..54e9023
--- /dev/null
+++ b/service/jni/jni_helper.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2008, 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 */
+
+void throwException( JNIEnv *env, const char *message, int line )
+{
+ ALOGE("error at line %d: %s", line, message);
+
+ const char *className = "java/lang/Exception";
+
+ jclass exClass = (env)->FindClass(className );
+ if ( exClass == NULL ) {
+ ALOGE("Could not find exception class to throw error");
+ ALOGE("error at line %d: %s", line, message);
+ return;
+ }
+
+ (env)->ThrowNew(exClass, message);
+}
+
+jlong getLongField(JNIEnv *env, jobject obj, const char *name)
+{
+ jclass cls = (env)->GetObjectClass(obj);
+ jfieldID field = (env)->GetFieldID(cls, name, "J");
+ if (field == 0) {
+ THROW(env, "Error in accessing field");
+ return 0;
+ }
+
+ jlong value = (env)->GetLongField(obj, field);
+ return value;
+}
+
+jlong getLongArrayField(JNIEnv *env, jobject obj, const char *name, int index)
+{
+ jclass cls = (env)->GetObjectClass(obj);
+ jfieldID field = (env)->GetFieldID(cls, name, "[J");
+ if (field == 0) {
+ THROW(env, "Error in accessing field definition");
+ return 0;
+ }
+
+ jlongArray array = (jlongArray)(env)->GetObjectField(obj, field);
+ jlong *elem = (env)->GetLongArrayElements(array, 0);
+ if (elem == NULL) {
+ THROW(env, "Error in accessing index element");
+ return 0;
+ }
+
+ jlong value = elem[index];
+ (env)->ReleaseLongArrayElements(array, elem, 0);
+ return value;
+}
+
+void setIntField(JNIEnv *env, jobject obj, const char *name, jint value)
+{
+ jclass cls = (env)->GetObjectClass(obj);
+ if (cls == NULL) {
+ THROW(env, "Error in accessing class");
+ return;
+ }
+
+ jfieldID field = (env)->GetFieldID(cls, name, "I");
+ if (field == NULL) {
+ THROW(env, "Error in accessing field");
+ return;
+ }
+
+ (env)->SetIntField(obj, field, value);
+}
+
+void setLongField(JNIEnv *env, jobject obj, const char *name, jlong value)
+{
+ jclass cls = (env)->GetObjectClass(obj);
+ if (cls == NULL) {
+ THROW(env, "Error in accessing class");
+ return;
+ }
+
+ jfieldID field = (env)->GetFieldID(cls, name, "J");
+ if (field == NULL) {
+ THROW(env, "Error in accessing field");
+ return;
+ }
+
+ (env)->SetLongField(obj, field, value);
+}
+
+void setLongArrayField(JNIEnv *env, jobject obj, const char *name, jlongArray value)
+{
+ ALOGD("setting long array field");
+
+ jclass cls = (env)->GetObjectClass(obj);
+ if (cls == NULL) {
+ THROW(env, "Error in accessing field");
+ return;
+ } else {
+ ALOGD("cls = %p", cls);
+ }
+
+ jfieldID field = (env)->GetFieldID(cls, name, "[J");
+ if (field == NULL) {
+ THROW(env, "Error in accessing field");
+ return;
+ }
+
+ (env)->SetObjectField(obj, field, value);
+ ALOGD("array field set");
+}
+
+void setLongArrayElement(JNIEnv *env, jobject obj, const char *name, int index, jlong value)
+{
+ jclass cls = (env)->GetObjectClass(obj);
+ if (cls == NULL) {
+ THROW(env, "Error in accessing field");
+ return;
+ } else {
+ ALOGD("cls = %p", cls);
+ }
+
+ jfieldID field = (env)->GetFieldID(cls, name, "[J");
+ if (field == NULL) {
+ THROW(env, "Error in accessing field");
+ return;
+ } else {
+ ALOGD("field = %p", field);
+ }
+
+ jlongArray array = (jlongArray)(env)->GetObjectField(obj, field);
+ if (array == NULL) {
+ THROW(env, "Error in accessing array");
+ return;
+ } else {
+ ALOGD("array = %p", array);
+ }
+
+ jlong *elem = (env)->GetLongArrayElements(array, NULL);
+ if (elem == NULL) {
+ THROW(env, "Error in accessing index element");
+ return;
+ }
+
+ elem[index] = value;
+ (env)->ReleaseLongArrayElements(array, elem, 0);
+}
+
+void setObjectField(JNIEnv *env, jobject obj, const char *name, const char *type, jobject value)
+{
+ jclass cls = (env)->GetObjectClass(obj);
+ if (cls == NULL) {
+ THROW(env, "Error in accessing class");
+ return;
+ }
+
+ jfieldID field = (env)->GetFieldID(cls, name, type);
+ if (field == NULL) {
+ THROW(env, "Error in accessing field");
+ return;
+ }
+
+ (env)->SetObjectField(obj, field, value);
+}
+
+void setStringField(JNIEnv *env, jobject obj, const char *name, const char *value)
+{
+
+ jstring str = env->NewStringUTF(value);
+
+ if (str == NULL) {
+ THROW(env, "Error in accessing class");
+ return;
+ }
+
+ setObjectField(env, obj, name, "Ljava/lang/String;", str);
+}
+
+void reportEvent(JNIEnv *env, jobject obj, const char *method, const char *signature, ...)
+{
+ va_list params;
+ va_start(params, signature);
+
+ jclass cls = (env)->GetObjectClass(obj);
+ if (cls == NULL) {
+ ALOGE("Error in accessing class");
+ return;
+ }
+
+ jmethodID methodID = env->GetMethodID(cls, method, signature);
+ if (method == NULL) {
+ ALOGE("Error in getting method ID");
+ return;
+ }
+
+ env->CallVoidMethodV(obj, methodID, params);
+ va_end(params);
+}
+
+jobject createObject(JNIEnv *env, const char *className)
+{
+ jclass cls = env->FindClass(className);
+ if (cls == NULL) {
+ ALOGE("Error in finding class");
+ return NULL;
+ }
+
+ jmethodID constructor = env->GetMethodID(cls, "<init>", "()V");
+ if (constructor == NULL) {
+ ALOGE("Error in constructor ID");
+ return NULL;
+ }
+ jobject obj = env->NewObject(cls, constructor);
+ if (constructor == NULL) {
+ ALOGE("Could not create new object of %s", className);
+ return NULL;
+ }
+
+ return obj;
+}
+
+}; // namespace android
+
+
diff --git a/service/jni/jni_helper.h b/service/jni/jni_helper.h
new file mode 100644
index 0000000..e61ee0a
--- /dev/null
+++ b/service/jni/jni_helper.h
@@ -0,0 +1,20 @@
+
+namespace android {
+
+/* JNI Helpers for wifi_hal to WifiNative bridge implementation */
+
+void throwException( JNIEnv *env, const char *message, int line );
+jlong getLongField(JNIEnv *env, jobject obj, const char *name);
+jlong getLongArrayField(JNIEnv *env, jobject obj, const char *name, int index);
+void setIntField(JNIEnv *env, jobject obj, const char *name, jint value);
+void setLongField(JNIEnv *env, jobject obj, const char *name, jlong value);
+void setLongArrayField(JNIEnv *env, jobject obj, const char *name, jlongArray value);
+void setLongArrayElement(JNIEnv *env, jobject obj, const char *name, int index, jlong value);
+void setStringField(JNIEnv *env, jobject obj, const char *name, const char *value);
+void reportEvent(JNIEnv *env, jobject obj, const char *method, const char *signature, ...);
+jobject createObject(JNIEnv *env, const char *className);
+void setObjectField(JNIEnv *env, jobject obj, const char *name, const char *type, jobject value);
+
+}
+
+#define THROW(env, message) throwException(env, message, __LINE__)