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(&params, 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
-