Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright 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 "wifi"
     18 
     19 #include "jni.h"
     20 #include <ScopedUtfChars.h>
     21 #include <utils/misc.h>
     22 #include <android_runtime/AndroidRuntime.h>
     23 #include <utils/Log.h>
     24 #include <utils/String16.h>
     25 #include <ctype.h>
     26 
     27 #include "wifi.h"
     28 #include "wifi_hal.h"
     29 #include "jni_helper.h"
     30 
     31 #define REPLY_BUF_SIZE 4096 // wpa_supplicant's maximum size.
     32 #define EVENT_BUF_SIZE 2048
     33 
     34 namespace android {
     35 
     36 static jint DBG = false;
     37 
     38 static bool doCommand(JNIEnv* env, jstring javaCommand,
     39                       char* reply, size_t reply_len) {
     40     ScopedUtfChars command(env, javaCommand);
     41     if (command.c_str() == NULL) {
     42         return false; // ScopedUtfChars already threw on error.
     43     }
     44 
     45     if (DBG) {
     46         ALOGD("doCommand: %s", command.c_str());
     47     }
     48 
     49     --reply_len; // Ensure we have room to add NUL termination.
     50     if (::wifi_command(command.c_str(), reply, &reply_len) != 0) {
     51         return false;
     52     }
     53 
     54     // Strip off trailing newline.
     55     if (reply_len > 0 && reply[reply_len-1] == '\n') {
     56         reply[reply_len-1] = '\0';
     57     } else {
     58         reply[reply_len] = '\0';
     59     }
     60     return true;
     61 }
     62 
     63 static jint doIntCommand(JNIEnv* env, jstring javaCommand) {
     64     char reply[REPLY_BUF_SIZE];
     65     if (!doCommand(env, javaCommand, reply, sizeof(reply))) {
     66         return -1;
     67     }
     68     return static_cast<jint>(atoi(reply));
     69 }
     70 
     71 static jboolean doBooleanCommand(JNIEnv* env, jstring javaCommand) {
     72     char reply[REPLY_BUF_SIZE];
     73     if (!doCommand(env, javaCommand, reply, sizeof(reply))) {
     74         return JNI_FALSE;
     75     }
     76     return (strcmp(reply, "OK") == 0);
     77 }
     78 
     79 // Send a command to the supplicant, and return the reply as a String.
     80 static jstring doStringCommand(JNIEnv* env, jstring javaCommand) {
     81     char reply[REPLY_BUF_SIZE];
     82     if (!doCommand(env, javaCommand, reply, sizeof(reply))) {
     83         return NULL;
     84     }
     85     return env->NewStringUTF(reply);
     86 }
     87 
     88 static jboolean android_net_wifi_isDriverLoaded(JNIEnv* env, jobject)
     89 {
     90     return (::is_wifi_driver_loaded() == 1);
     91 }
     92 
     93 static jboolean android_net_wifi_loadDriver(JNIEnv* env, jobject)
     94 {
     95     return (::wifi_load_driver() == 0);
     96 }
     97 
     98 static jboolean android_net_wifi_unloadDriver(JNIEnv* env, jobject)
     99 {
    100     return (::wifi_unload_driver() == 0);
    101 }
    102 
    103 static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject, jboolean p2pSupported)
    104 {
    105     return (::wifi_start_supplicant(p2pSupported) == 0);
    106 }
    107 
    108 static jboolean android_net_wifi_killSupplicant(JNIEnv* env, jobject, jboolean p2pSupported)
    109 {
    110     return (::wifi_stop_supplicant(p2pSupported) == 0);
    111 }
    112 
    113 static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jobject)
    114 {
    115     return (::wifi_connect_to_supplicant() == 0);
    116 }
    117 
    118 static void android_net_wifi_closeSupplicantConnection(JNIEnv* env, jobject)
    119 {
    120     ::wifi_close_supplicant_connection();
    121 }
    122 
    123 static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject)
    124 {
    125     char buf[EVENT_BUF_SIZE];
    126     int nread = ::wifi_wait_for_event(buf, sizeof buf);
    127     if (nread > 0) {
    128         return env->NewStringUTF(buf);
    129     } else {
    130         return NULL;
    131     }
    132 }
    133 
    134 static jboolean android_net_wifi_doBooleanCommand(JNIEnv* env, jobject, jstring javaCommand) {
    135     return doBooleanCommand(env, javaCommand);
    136 }
    137 
    138 static jint android_net_wifi_doIntCommand(JNIEnv* env, jobject, jstring javaCommand) {
    139     return doIntCommand(env, javaCommand);
    140 }
    141 
    142 static jstring android_net_wifi_doStringCommand(JNIEnv* env, jobject, jstring javaCommand) {
    143     return doStringCommand(env,javaCommand);
    144 }
    145 
    146 /* wifi_hal <==> WifiNative bridge */
    147 
    148 static jclass mCls;                             /* saved WifiNative object */
    149 static JavaVM *mVM;                             /* saved JVM pointer */
    150 
    151 static const char *WifiHandleVarName = "sWifiHalHandle";
    152 static const char *WifiIfaceHandleVarName = "sWifiIfaceHandles";
    153 static jmethodID OnScanResultsMethodID;
    154 
    155 static JNIEnv *getEnv() {
    156     JNIEnv *env = NULL;
    157     mVM->AttachCurrentThread(&env, NULL);
    158     return env;
    159 }
    160 
    161 static wifi_handle getWifiHandle(JNIEnv *env, jclass cls) {
    162     return (wifi_handle) getStaticLongField(env, cls, WifiHandleVarName);
    163 }
    164 
    165 static wifi_interface_handle getIfaceHandle(JNIEnv *env, jclass cls, jint index) {
    166     return (wifi_interface_handle) getStaticLongArrayField(env, cls, WifiIfaceHandleVarName, index);
    167 }
    168 
    169 static jobject createScanResult(JNIEnv *env, wifi_scan_result *result) {
    170 
    171     // ALOGD("creating scan result");
    172 
    173     jobject scanResult = createObject(env, "android/net/wifi/ScanResult");
    174     if (scanResult == NULL) {
    175         ALOGE("Error in creating scan result");
    176         return NULL;
    177     }
    178 
    179     // ALOGD("setting SSID to %s", result.ssid);
    180     setStringField(env, scanResult, "SSID", result->ssid);
    181 
    182     char bssid[32];
    183     sprintf(bssid, "%02x:%02x:%02x:%02x:%02x:%02x", result->bssid[0], result->bssid[1],
    184         result->bssid[2], result->bssid[3], result->bssid[4], result->bssid[5]);
    185 
    186     setStringField(env, scanResult, "BSSID", bssid);
    187 
    188     setIntField(env, scanResult, "level", result->rssi);
    189     setIntField(env, scanResult, "frequency", result->channel);
    190     setLongField(env, scanResult, "timestamp", result->ts);
    191 
    192     return scanResult;
    193 }
    194 
    195 static jboolean android_net_wifi_startHal(JNIEnv* env, jclass cls) {
    196     wifi_handle halHandle = getWifiHandle(env, cls);
    197 
    198     if (halHandle == NULL) {
    199         wifi_error res = wifi_initialize(&halHandle);
    200         if (res == WIFI_SUCCESS) {
    201             setStaticLongField(env, cls, WifiHandleVarName, (jlong)halHandle);
    202             ALOGD("Did set static halHandle = %p", halHandle);
    203         }
    204         env->GetJavaVM(&mVM);
    205         mCls = (jclass) env->NewGlobalRef(cls);
    206         ALOGD("halHandle = %p, mVM = %p, mCls = %p", halHandle, mVM, mCls);
    207         return res == WIFI_SUCCESS;
    208     } else {
    209         return true;
    210     }
    211 }
    212 
    213 void android_net_wifi_hal_cleaned_up_handler(wifi_handle handle) {
    214     ALOGD("In wifi cleaned up handler");
    215 
    216     JNIEnv * env = getEnv();
    217     setStaticLongField(env, mCls, WifiHandleVarName, 0);
    218     env->DeleteGlobalRef(mCls);
    219     mCls = NULL;
    220     mVM  = NULL;
    221 }
    222 
    223 static void android_net_wifi_stopHal(JNIEnv* env, jclass cls) {
    224     ALOGD("In wifi stop Hal");
    225     wifi_handle halHandle = getWifiHandle(env, cls);
    226     wifi_cleanup(halHandle, android_net_wifi_hal_cleaned_up_handler);
    227 }
    228 
    229 static void android_net_wifi_waitForHalEvents(JNIEnv* env, jclass cls) {
    230 
    231     ALOGD("waitForHalEvents called, vm = %p, obj = %p, env = %p", mVM, mCls, env);
    232 
    233     wifi_handle halHandle = getWifiHandle(env, cls);
    234     wifi_event_loop(halHandle);
    235 }
    236 
    237 static int android_net_wifi_getInterfaces(JNIEnv *env, jclass cls) {
    238     int n = 0;
    239     wifi_handle halHandle = getWifiHandle(env, cls);
    240     wifi_interface_handle *ifaceHandles = NULL;
    241     int result = wifi_get_ifaces(halHandle, &n, &ifaceHandles);
    242     if (result < 0) {
    243         return result;
    244     }
    245 
    246     if (n < 0) {
    247         THROW(env, "android_net_wifi_getInterfaces no interfaces");
    248         return 0;
    249     }
    250 
    251     if (ifaceHandles == NULL) {
    252        THROW(env, "android_net_wifi_getInterfaces null interface array");
    253        return 0;
    254     }
    255 
    256     if (n > 8) {
    257         THROW(env, "Too many interfaces");
    258         return 0;
    259     }
    260 
    261     jlongArray array = (env)->NewLongArray(n);
    262     if (array == NULL) {
    263         THROW(env, "Error in accessing array");
    264         return 0;
    265     }
    266 
    267     jlong elems[8];
    268     for (int i = 0; i < n; i++) {
    269         elems[i] = reinterpret_cast<jlong>(ifaceHandles[i]);
    270     }
    271     env->SetLongArrayRegion(array, 0, n, elems);
    272     setStaticLongArrayField(env, cls, WifiIfaceHandleVarName, array);
    273 
    274     return (result < 0) ? result : n;
    275 }
    276 
    277 static jstring android_net_wifi_getInterfaceName(JNIEnv *env, jclass cls, jint i) {
    278     char buf[EVENT_BUF_SIZE];
    279 
    280     jlong value = getStaticLongArrayField(env, cls, WifiIfaceHandleVarName, i);
    281     wifi_interface_handle handle = (wifi_interface_handle) value;
    282     int result = ::wifi_get_iface_name(handle, buf, sizeof(buf));
    283     if (result < 0) {
    284         return NULL;
    285     } else {
    286         return env->NewStringUTF(buf);
    287     }
    288 }
    289 
    290 
    291 static void onScanResultsAvailable(wifi_request_id id, unsigned num_results) {
    292 
    293     JNIEnv *env = NULL;
    294     mVM->AttachCurrentThread(&env, NULL);
    295 
    296     ALOGD("onScanResultsAvailable called, vm = %p, obj = %p, env = %p", mVM, mCls, env);
    297 
    298     reportEvent(env, mCls, "onScanResultsAvailable", "(I)V", id);
    299 }
    300 
    301 static void onScanEvent(wifi_scan_event event, unsigned status) {
    302     JNIEnv *env = NULL;
    303     mVM->AttachCurrentThread(&env, NULL);
    304 
    305     ALOGD("onScanStatus called, vm = %p, obj = %p, env = %p", mVM, mCls, env);
    306 
    307     reportEvent(env, mCls, "onScanStatus", "(I)V", status);
    308 }
    309 
    310 static void onFullScanResult(wifi_request_id id, wifi_scan_result *result) {
    311 
    312     JNIEnv *env = NULL;
    313     mVM->AttachCurrentThread(&env, NULL);
    314 
    315     ALOGD("onFullScanResult called, vm = %p, obj = %p, env = %p", mVM, mCls, env);
    316 
    317     jobject scanResult = createScanResult(env, result);
    318 
    319     ALOGD("Creating a byte array of length %d", result->ie_length);
    320 
    321     jbyteArray elements = env->NewByteArray(result->ie_length);
    322     if (elements == NULL) {
    323         ALOGE("Error in allocating array");
    324         return;
    325     }
    326 
    327     ALOGE("Setting byte array");
    328 
    329     jbyte *bytes = (jbyte *)&(result->ie_data[0]);
    330     env->SetByteArrayRegion(elements, 0, result->ie_length, bytes);
    331 
    332     ALOGE("Returning result");
    333 
    334     reportEvent(env, mCls, "onFullScanResult", "(ILandroid/net/wifi/ScanResult;[B)V", id,
    335             scanResult, elements);
    336 
    337     env->DeleteLocalRef(scanResult);
    338     env->DeleteLocalRef(elements);
    339 }
    340 
    341 static jboolean android_net_wifi_startScan(
    342         JNIEnv *env, jclass cls, jint iface, jint id, jobject settings) {
    343 
    344     wifi_interface_handle handle = getIfaceHandle(env, cls, iface);
    345     ALOGD("starting scan on interface[%d] = %p", iface, handle);
    346 
    347     wifi_scan_cmd_params params;
    348     memset(&params, 0, sizeof(params));
    349 
    350     params.base_period = getIntField(env, settings, "base_period_ms");
    351     params.max_ap_per_scan = getIntField(env, settings, "max_ap_per_scan");
    352     params.report_threshold = getIntField(env, settings, "report_threshold");
    353 
    354     ALOGD("Initialized common fields %d, %d, %d", params.base_period,
    355             params.max_ap_per_scan, params.report_threshold);
    356 
    357     const char *bucket_array_type = "[Lcom/android/server/wifi/WifiNative$BucketSettings;";
    358     const char *channel_array_type = "[Lcom/android/server/wifi/WifiNative$ChannelSettings;";
    359 
    360     jobjectArray buckets = (jobjectArray)getObjectField(env, settings, "buckets", bucket_array_type);
    361     params.num_buckets = getIntField(env, settings, "num_buckets");
    362 
    363     ALOGD("Initialized num_buckets to %d", params.num_buckets);
    364 
    365     for (int i = 0; i < params.num_buckets; i++) {
    366         jobject bucket = getObjectArrayField(env, settings, "buckets", bucket_array_type, i);
    367 
    368         params.buckets[i].bucket = getIntField(env, bucket, "bucket");
    369         params.buckets[i].band = (wifi_band) getIntField(env, bucket, "band");
    370         params.buckets[i].period = getIntField(env, bucket, "period_ms");
    371 
    372         ALOGD("Initialized common bucket fields %d:%d:%d", params.buckets[i].bucket,
    373                 params.buckets[i].band, params.buckets[i].period);
    374 
    375         int report_events = getIntField(env, bucket, "report_events");
    376         params.buckets[i].report_events = report_events;
    377 
    378         ALOGD("Initialized report events to %d", params.buckets[i].report_events);
    379 
    380         jobjectArray channels = (jobjectArray)getObjectField(
    381                 env, bucket, "channels", channel_array_type);
    382 
    383         params.buckets[i].num_channels = getIntField(env, bucket, "num_channels");
    384         ALOGD("Initialized num_channels to %d", params.buckets[i].num_channels);
    385 
    386         for (int j = 0; j < params.buckets[i].num_channels; j++) {
    387             jobject channel = getObjectArrayField(env, bucket, "channels", channel_array_type, j);
    388 
    389             params.buckets[i].channels[j].channel = getIntField(env, channel, "frequency");
    390             params.buckets[i].channels[j].dwellTimeMs = getIntField(env, channel, "dwell_time_ms");
    391 
    392             bool passive = getBoolField(env, channel, "passive");
    393             params.buckets[i].channels[j].passive = (passive ? 1 : 0);
    394 
    395             ALOGD("Initialized channel %d", params.buckets[i].channels[j].channel);
    396         }
    397     }
    398 
    399     ALOGD("Initialized all fields");
    400 
    401     wifi_scan_result_handler handler;
    402     memset(&handler, 0, sizeof(handler));
    403     handler.on_scan_results_available = &onScanResultsAvailable;
    404     handler.on_full_scan_result = &onFullScanResult;
    405     handler.on_scan_event = &onScanEvent;
    406 
    407     return wifi_start_gscan(id, handle, params, handler) == WIFI_SUCCESS;
    408 }
    409 
    410 static jboolean android_net_wifi_stopScan(JNIEnv *env, jclass cls, jint iface, jint id) {
    411     wifi_interface_handle handle = getIfaceHandle(env, cls, iface);
    412     ALOGD("stopping scan on interface[%d] = %p", iface, handle);
    413 
    414     return wifi_stop_gscan(id, handle)  == WIFI_SUCCESS;
    415 }
    416 
    417 static jobject android_net_wifi_getScanResults(
    418         JNIEnv *env, jclass cls, jint iface, jboolean flush)  {
    419 
    420     wifi_scan_result results[256];
    421     int num_results = 256;
    422 
    423     wifi_interface_handle handle = getIfaceHandle(env, cls, iface);
    424     ALOGD("getting scan results on interface[%d] = %p", iface, handle);
    425 
    426     int result = wifi_get_cached_gscan_results(handle, 1, num_results, results, &num_results);
    427     if (result == WIFI_SUCCESS) {
    428         jclass clsScanResult = (env)->FindClass("android/net/wifi/ScanResult");
    429         if (clsScanResult == NULL) {
    430             ALOGE("Error in accessing class");
    431             return NULL;
    432         }
    433 
    434         jobjectArray scanResults = env->NewObjectArray(num_results, clsScanResult, NULL);
    435         if (scanResults == NULL) {
    436             ALOGE("Error in allocating array");
    437             return NULL;
    438         }
    439 
    440         for (int i = 0; i < num_results; i++) {
    441 
    442             jobject scanResult = createObject(env, "android/net/wifi/ScanResult");
    443             if (scanResult == NULL) {
    444                 ALOGE("Error in creating scan result");
    445                 return NULL;
    446             }
    447 
    448             setStringField(env, scanResult, "SSID", results[i].ssid);
    449 
    450             char bssid[32];
    451             sprintf(bssid, "%02x:%02x:%02x:%02x:%02x:%02x", results[i].bssid[0],
    452                     results[i].bssid[1], results[i].bssid[2], results[i].bssid[3],
    453                     results[i].bssid[4], results[i].bssid[5]);
    454 
    455             setStringField(env, scanResult, "BSSID", bssid);
    456 
    457             setIntField(env, scanResult, "level", results[i].rssi);
    458             setIntField(env, scanResult, "frequency", results[i].channel);
    459             setLongField(env, scanResult, "timestamp", results[i].ts);
    460 
    461             env->SetObjectArrayElement(scanResults, i, scanResult);
    462             env->DeleteLocalRef(scanResult);
    463         }
    464 
    465         return scanResults;
    466     } else {
    467         return NULL;
    468     }
    469 }
    470 
    471 
    472 static jboolean android_net_wifi_getScanCapabilities(
    473         JNIEnv *env, jclass cls, jint iface, jobject capabilities) {
    474 
    475     wifi_interface_handle handle = getIfaceHandle(env, cls, iface);
    476     ALOGD("getting scan capabilities on interface[%d] = %p", iface, handle);
    477 
    478     wifi_gscan_capabilities c;
    479     memset(&c, 0, sizeof(c));
    480     int result = wifi_get_gscan_capabilities(handle, &c);
    481     if (result != WIFI_SUCCESS) {
    482         ALOGD("failed to get capabilities : %d", result);
    483         return JNI_FALSE;
    484     }
    485 
    486     setIntField(env, capabilities, "max_scan_cache_size", c.max_scan_cache_size);
    487     setIntField(env, capabilities, "max_scan_buckets", c.max_scan_buckets);
    488     setIntField(env, capabilities, "max_ap_cache_per_scan", c.max_ap_cache_per_scan);
    489     setIntField(env, capabilities, "max_rssi_sample_size", c.max_rssi_sample_size);
    490     setIntField(env, capabilities, "max_scan_reporting_threshold", c.max_scan_reporting_threshold);
    491     setIntField(env, capabilities, "max_hotlist_aps", c.max_hotlist_aps);
    492     setIntField(env, capabilities, "max_significant_wifi_change_aps",
    493                 c.max_significant_wifi_change_aps);
    494 
    495     return JNI_TRUE;
    496 }
    497 
    498 
    499 static byte parseHexChar(char ch) {
    500     if (isdigit(ch))
    501         return ch - '0';
    502     else if ('A' <= ch && ch <= 'F')
    503         return ch - 'A' + 10;
    504     else if ('a' <= ch && ch <= 'f')
    505         return ch - 'a' + 10;
    506     else {
    507         ALOGE("invalid character in bssid %c", ch);
    508         return 0;
    509     }
    510 }
    511 
    512 static byte parseHexByte(const char * &str) {
    513     byte b = parseHexChar(str[0]);
    514     if (str[1] == ':' || str[1] == '\0') {
    515         str += 2;
    516         return b;
    517     } else {
    518         b = b << 4 | parseHexChar(str[1]);
    519         str += 3;
    520         return b;
    521     }
    522 }
    523 
    524 static void parseMacAddress(const char *str, mac_addr addr) {
    525     addr[0] = parseHexByte(str);
    526     addr[1] = parseHexByte(str);
    527     addr[2] = parseHexByte(str);
    528     addr[3] = parseHexByte(str);
    529     addr[4] = parseHexByte(str);
    530     addr[5] = parseHexByte(str);
    531 }
    532 
    533 static bool parseMacAddress(JNIEnv *env, jobject obj, mac_addr addr) {
    534     jstring macAddrString = (jstring) getObjectField(
    535             env, obj, "bssid", "Ljava/lang/String;");
    536 
    537     if (macAddrString == NULL) {
    538         ALOGE("Error getting bssid field");
    539         return false;
    540     }
    541 
    542     const char *bssid = env->GetStringUTFChars(macAddrString, NULL);
    543     if (bssid == NULL) {
    544         ALOGE("Error getting bssid");
    545         return false;
    546     }
    547 
    548     parseMacAddress(bssid, addr);
    549     return true;
    550 }
    551 
    552 static void onHotlistApFound(wifi_request_id id,
    553         unsigned num_results, wifi_scan_result *results) {
    554 
    555     JNIEnv *env = NULL;
    556     mVM->AttachCurrentThread(&env, NULL);
    557 
    558     ALOGD("onHotlistApFound called, vm = %p, obj = %p, env = %p, num_results = %d",
    559             mVM, mCls, env, num_results);
    560 
    561     jclass clsScanResult = (env)->FindClass("android/net/wifi/ScanResult");
    562     if (clsScanResult == NULL) {
    563         ALOGE("Error in accessing class");
    564         return;
    565     }
    566 
    567     jobjectArray scanResults = env->NewObjectArray(num_results, clsScanResult, NULL);
    568     if (scanResults == NULL) {
    569         ALOGE("Error in allocating array");
    570         return;
    571     }
    572 
    573     for (unsigned i = 0; i < num_results; i++) {
    574 
    575         jobject scanResult = createObject(env, "android/net/wifi/ScanResult");
    576         if (scanResult == NULL) {
    577             ALOGE("Error in creating scan result");
    578             return;
    579         }
    580 
    581         setStringField(env, scanResult, "SSID", results[i].ssid);
    582 
    583         char bssid[32];
    584         sprintf(bssid, "%02x:%02x:%02x:%02x:%02x:%02x", results[i].bssid[0], results[i].bssid[1],
    585             results[i].bssid[2], results[i].bssid[3], results[i].bssid[4], results[i].bssid[5]);
    586 
    587         setStringField(env, scanResult, "BSSID", bssid);
    588 
    589         setIntField(env, scanResult, "level", results[i].rssi);
    590         setIntField(env, scanResult, "frequency", results[i].channel);
    591         setLongField(env, scanResult, "timestamp", results[i].ts);
    592 
    593         env->SetObjectArrayElement(scanResults, i, scanResult);
    594 
    595         ALOGD("Found AP %32s %s", results[i].ssid, bssid);
    596     }
    597 
    598     reportEvent(env, mCls, "onHotlistApFound", "(I[Landroid/net/wifi/ScanResult;)V",
    599         id, scanResults);
    600 }
    601 
    602 static jboolean android_net_wifi_setHotlist(
    603         JNIEnv *env, jclass cls, jint iface, jint id, jobject ap)  {
    604 
    605     wifi_interface_handle handle = getIfaceHandle(env, cls, iface);
    606     ALOGD("setting hotlist on interface[%d] = %p", iface, handle);
    607 
    608     wifi_bssid_hotlist_params params;
    609     memset(&params, 0, sizeof(params));
    610 
    611     jobjectArray array = (jobjectArray) getObjectField(env, ap,
    612             "bssidInfos", "[Landroid/net/wifi/WifiScanner$BssidInfo;");
    613     params.num_ap = env->GetArrayLength(array);
    614 
    615     if (params.num_ap == 0) {
    616         ALOGE("Error in accesing array");
    617         return false;
    618     }
    619 
    620     for (int i = 0; i < params.num_ap; i++) {
    621         jobject objAp = env->GetObjectArrayElement(array, i);
    622 
    623         jstring macAddrString = (jstring) getObjectField(
    624                 env, objAp, "bssid", "Ljava/lang/String;");
    625         if (macAddrString == NULL) {
    626             ALOGE("Error getting bssid field");
    627             return false;
    628         }
    629 
    630         const char *bssid = env->GetStringUTFChars(macAddrString, NULL);
    631         if (bssid == NULL) {
    632             ALOGE("Error getting bssid");
    633             return false;
    634         }
    635         parseMacAddress(bssid, params.ap[i].bssid);
    636 
    637         mac_addr addr;
    638         memcpy(addr, params.ap[i].bssid, sizeof(mac_addr));
    639 
    640         char bssidOut[32];
    641         sprintf(bssidOut, "%0x:%0x:%0x:%0x:%0x:%0x", addr[0], addr[1],
    642             addr[2], addr[3], addr[4], addr[5]);
    643 
    644         ALOGD("Added bssid %s", bssidOut);
    645 
    646         params.ap[i].low = getIntField(env, objAp, "low");
    647         params.ap[i].high = getIntField(env, objAp, "high");
    648     }
    649 
    650     wifi_hotlist_ap_found_handler handler;
    651     memset(&handler, 0, sizeof(handler));
    652 
    653     handler.on_hotlist_ap_found = &onHotlistApFound;
    654     return wifi_set_bssid_hotlist(id, handle, params, handler) == WIFI_SUCCESS;
    655 }
    656 
    657 static jboolean android_net_wifi_resetHotlist(
    658         JNIEnv *env, jclass cls, jint iface, jint id)  {
    659 
    660     wifi_interface_handle handle = getIfaceHandle(env, cls, iface);
    661     ALOGD("resetting hotlist on interface[%d] = %p", iface, handle);
    662 
    663     return wifi_reset_bssid_hotlist(id, handle) == WIFI_SUCCESS;
    664 }
    665 
    666 void onSignificantWifiChange(wifi_request_id id,
    667         unsigned num_results, wifi_significant_change_result **results) {
    668     JNIEnv *env = NULL;
    669     mVM->AttachCurrentThread(&env, NULL);
    670 
    671     ALOGD("onSignificantWifiChange called, vm = %p, obj = %p, env = %p", mVM, mCls, env);
    672 
    673     jclass clsScanResult = (env)->FindClass("android/net/wifi/ScanResult");
    674     if (clsScanResult == NULL) {
    675         ALOGE("Error in accessing class");
    676         return;
    677     }
    678 
    679     jobjectArray scanResults = env->NewObjectArray(num_results, clsScanResult, NULL);
    680     if (scanResults == NULL) {
    681         ALOGE("Error in allocating array");
    682         return;
    683     }
    684 
    685     for (unsigned i = 0; i < num_results; i++) {
    686 
    687         wifi_significant_change_result result = *(results[i]);
    688 
    689         jobject scanResult = createObject(env, "android/net/wifi/ScanResult");
    690         if (scanResult == NULL) {
    691             ALOGE("Error in creating scan result");
    692             return;
    693         }
    694 
    695         // setStringField(env, scanResult, "SSID", results[i].ssid);
    696 
    697         char bssid[32];
    698         sprintf(bssid, "%02x:%02x:%02x:%02x:%02x:%02x", result.bssid[0], result.bssid[1],
    699             result.bssid[2], result.bssid[3], result.bssid[4], result.bssid[5]);
    700 
    701         setStringField(env, scanResult, "BSSID", bssid);
    702 
    703         setIntField(env, scanResult, "level", result.rssi[0]);
    704         setIntField(env, scanResult, "frequency", result.channel);
    705         // setLongField(env, scanResult, "timestamp", result.ts);
    706 
    707         env->SetObjectArrayElement(scanResults, i, scanResult);
    708     }
    709 
    710     reportEvent(env, mCls, "onSignificantWifiChange", "(I[Landroid/net/wifi/ScanResult;)V",
    711         id, scanResults);
    712 
    713 }
    714 
    715 static jboolean android_net_wifi_trackSignificantWifiChange(
    716         JNIEnv *env, jclass cls, jint iface, jint id, jobject settings)  {
    717 
    718     wifi_interface_handle handle = getIfaceHandle(env, cls, iface);
    719     ALOGD("tracking significant wifi change on interface[%d] = %p", iface, handle);
    720 
    721     wifi_significant_change_params params;
    722     memset(&params, 0, sizeof(params));
    723 
    724     params.rssi_sample_size = getIntField(env, settings, "rssiSampleSize");
    725     params.lost_ap_sample_size = getIntField(env, settings, "lostApSampleSize");
    726     params.min_breaching = getIntField(env, settings, "minApsBreachingThreshold");
    727 
    728     const char *bssid_info_array_type = "[Landroid/net/wifi/WifiScanner$BssidInfo;";
    729     jobjectArray bssids = (jobjectArray)getObjectField(
    730                 env, settings, "bssidInfos", bssid_info_array_type);
    731     params.num_ap = env->GetArrayLength(bssids);
    732 
    733     if (params.num_ap == 0) {
    734         ALOGE("Error in accessing array");
    735         return false;
    736     }
    737 
    738     ALOGD("Initialized common fields %d, %d, %d, %d", params.rssi_sample_size,
    739             params.lost_ap_sample_size, params.min_breaching, params.num_ap);
    740 
    741     for (int i = 0; i < params.num_ap; i++) {
    742         jobject objAp = env->GetObjectArrayElement(bssids, i);
    743 
    744         jstring macAddrString = (jstring) getObjectField(
    745                 env, objAp, "bssid", "Ljava/lang/String;");
    746         if (macAddrString == NULL) {
    747             ALOGE("Error getting bssid field");
    748             return false;
    749         }
    750 
    751         const char *bssid = env->GetStringUTFChars(macAddrString, NULL);
    752         if (bssid == NULL) {
    753             ALOGE("Error getting bssid");
    754             return false;
    755         }
    756 
    757         mac_addr addr;
    758         parseMacAddress(bssid, addr);
    759         memcpy(params.ap[i].bssid, addr, sizeof(mac_addr));
    760 
    761         char bssidOut[32];
    762         sprintf(bssidOut, "%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1],
    763             addr[2], addr[3], addr[4], addr[5]);
    764 
    765         params.ap[i].low = getIntField(env, objAp, "low");
    766         params.ap[i].high = getIntField(env, objAp, "high");
    767 
    768         ALOGD("Added bssid %s, [%04d, %04d]", bssidOut, params.ap[i].low, params.ap[i].high);
    769     }
    770 
    771     ALOGD("Added %d bssids", params.num_ap);
    772 
    773     wifi_significant_change_handler handler;
    774     memset(&handler, 0, sizeof(handler));
    775 
    776     handler.on_significant_change = &onSignificantWifiChange;
    777     return wifi_set_significant_change_handler(id, handle, params, handler) == WIFI_SUCCESS;
    778 }
    779 
    780 static jboolean android_net_wifi_untrackSignificantWifiChange(
    781         JNIEnv *env, jclass cls, jint iface, jint id)  {
    782 
    783     wifi_interface_handle handle = getIfaceHandle(env, cls, iface);
    784     ALOGD("resetting significant wifi change on interface[%d] = %p", iface, handle);
    785 
    786     return wifi_reset_significant_change_handler(id, handle) == WIFI_SUCCESS;
    787 }
    788 
    789 wifi_iface_stat link_stat;
    790 wifi_radio_stat radio_stat; // L release has support for only one radio
    791 
    792 void onLinkStatsResults(wifi_request_id id, wifi_iface_stat *iface_stat,
    793          int num_radios, wifi_radio_stat *radio_stats)
    794 {
    795     if (iface_stat != 0) {
    796         memcpy(&link_stat, iface_stat, sizeof(wifi_iface_stat));
    797     } else {
    798         memset(&link_stat, 0, sizeof(wifi_iface_stat));
    799     }
    800 
    801     if (num_radios > 0 && radio_stats != 0) {
    802         memcpy(&radio_stat, radio_stats, sizeof(wifi_radio_stat));
    803     } else {
    804         memset(&radio_stat, 0, sizeof(wifi_radio_stat));
    805     }
    806 }
    807 
    808 static jobject android_net_wifi_getLinkLayerStats (JNIEnv *env, jclass cls, jint iface)  {
    809 
    810     wifi_stats_result_handler handler;
    811     memset(&handler, 0, sizeof(handler));
    812     handler.on_link_stats_results = &onLinkStatsResults;
    813     wifi_interface_handle handle = getIfaceHandle(env, cls, iface);
    814     int result = wifi_get_link_stats(0, handle, handler);
    815     if (result < 0) {
    816         ALOGE("android_net_wifi_getLinkLayerStats: failed to get link statistics\n");
    817         return NULL;
    818     }
    819 
    820     jobject wifiLinkLayerStats = createObject(env, "android/net/wifi/WifiLinkLayerStats");
    821     if (wifiLinkLayerStats == NULL) {
    822        ALOGE("Error in allocating wifiLinkLayerStats");
    823        return NULL;
    824     }
    825 
    826     setIntField(env, wifiLinkLayerStats, "beacon_rx", link_stat.beacon_rx);
    827     setIntField(env, wifiLinkLayerStats, "rssi_mgmt", link_stat.rssi_mgmt);
    828     setLongField(env, wifiLinkLayerStats, "rxmpdu_be", link_stat.ac[WIFI_AC_BE].rx_mpdu);
    829     setLongField(env, wifiLinkLayerStats, "rxmpdu_bk", link_stat.ac[WIFI_AC_BK].rx_mpdu);
    830     setLongField(env, wifiLinkLayerStats, "rxmpdu_vi", link_stat.ac[WIFI_AC_VI].rx_mpdu);
    831     setLongField(env, wifiLinkLayerStats, "rxmpdu_vo", link_stat.ac[WIFI_AC_VO].rx_mpdu);
    832     setLongField(env, wifiLinkLayerStats, "txmpdu_be", link_stat.ac[WIFI_AC_BE].tx_mpdu);
    833     setLongField(env, wifiLinkLayerStats, "txmpdu_bk", link_stat.ac[WIFI_AC_BK].tx_mpdu);
    834     setLongField(env, wifiLinkLayerStats, "txmpdu_vi", link_stat.ac[WIFI_AC_VI].tx_mpdu);
    835     setLongField(env, wifiLinkLayerStats, "txmpdu_vo", link_stat.ac[WIFI_AC_VO].tx_mpdu);
    836     setLongField(env, wifiLinkLayerStats, "lostmpdu_be", link_stat.ac[WIFI_AC_BE].mpdu_lost);
    837     setLongField(env, wifiLinkLayerStats, "lostmpdu_bk", link_stat.ac[WIFI_AC_BK].mpdu_lost);
    838     setLongField(env, wifiLinkLayerStats, "lostmpdu_vi",  link_stat.ac[WIFI_AC_VI].mpdu_lost);
    839     setLongField(env, wifiLinkLayerStats, "lostmpdu_vo", link_stat.ac[WIFI_AC_VO].mpdu_lost);
    840     setLongField(env, wifiLinkLayerStats, "retries_be", link_stat.ac[WIFI_AC_BE].retries);
    841     setLongField(env, wifiLinkLayerStats, "retries_bk", link_stat.ac[WIFI_AC_BK].retries);
    842     setLongField(env, wifiLinkLayerStats, "retries_vi", link_stat.ac[WIFI_AC_VI].retries);
    843     setLongField(env, wifiLinkLayerStats, "retries_vo", link_stat.ac[WIFI_AC_VO].retries);
    844 
    845 
    846     setIntField(env, wifiLinkLayerStats, "on_time", radio_stat.on_time);
    847     setIntField(env, wifiLinkLayerStats, "tx_time", radio_stat.tx_time);
    848     setIntField(env, wifiLinkLayerStats, "rx_time", radio_stat.rx_time);
    849     setIntField(env, wifiLinkLayerStats, "on_time_scan", radio_stat.on_time_scan);
    850 
    851     return wifiLinkLayerStats;
    852 }
    853 
    854 static jint android_net_wifi_getSupportedFeatures(JNIEnv *env, jclass cls, jint iface) {
    855     wifi_interface_handle handle = getIfaceHandle(env, cls, iface);
    856     feature_set set = 0;
    857 
    858     wifi_error result = WIFI_SUCCESS;
    859     /*
    860     set = WIFI_FEATURE_INFRA
    861         | WIFI_FEATURE_INFRA_5G
    862         | WIFI_FEATURE_HOTSPOT
    863         | WIFI_FEATURE_P2P
    864         | WIFI_FEATURE_SOFT_AP
    865         | WIFI_FEATURE_GSCAN
    866         | WIFI_FEATURE_PNO
    867         | WIFI_FEATURE_TDLS
    868         | WIFI_FEATURE_EPR;
    869     */
    870 
    871     result = wifi_get_supported_feature_set(handle, &set);
    872     if (result == WIFI_SUCCESS) {
    873         /* Temporary workaround for RTT capability */
    874         set = set | WIFI_FEATURE_D2AP_RTT;
    875         ALOGD("wifi_get_supported_feature_set returned set = 0x%x", set);
    876         return set;
    877     } else {
    878         ALOGD("wifi_get_supported_feature_set returned error = 0x%x", result);
    879         return 0;
    880     }
    881 }
    882 
    883 static void onRttResults(wifi_request_id id, unsigned num_results, wifi_rtt_result results[]) {
    884     JNIEnv *env = NULL;
    885     mVM->AttachCurrentThread(&env, NULL);
    886 
    887     ALOGD("onRttResults called, vm = %p, obj = %p, env = %p", mVM, mCls, env);
    888 
    889     jclass clsRttResult = (env)->FindClass("android/net/wifi/RttManager$RttResult");
    890     if (clsRttResult == NULL) {
    891         ALOGE("Error in accessing class");
    892         return;
    893     }
    894 
    895     jobjectArray rttResults = env->NewObjectArray(num_results, clsRttResult, NULL);
    896     if (rttResults == NULL) {
    897         ALOGE("Error in allocating array");
    898         return;
    899     }
    900 
    901     for (unsigned i = 0; i < num_results; i++) {
    902 
    903         wifi_rtt_result& result = results[i];
    904 
    905         jobject rttResult = createObject(env, "android/net/wifi/RttManager$RttResult");
    906         if (rttResult == NULL) {
    907             ALOGE("Error in creating rtt result");
    908             return;
    909         }
    910 
    911         char bssid[32];
    912         sprintf(bssid, "%02x:%02x:%02x:%02x:%02x:%02x", result.addr[0], result.addr[1],
    913             result.addr[2], result.addr[3], result.addr[4], result.addr[5]);
    914 
    915         setStringField(env, rttResult, "bssid", bssid);
    916         setIntField(env,  rttResult, "status",               result.status);
    917         setIntField(env,  rttResult, "requestType",          result.type);
    918         setLongField(env, rttResult, "ts",                   result.ts);
    919         setIntField(env,  rttResult, "rssi",                 result.rssi);
    920         setIntField(env,  rttResult, "rssi_spread",          result.rssi_spread);
    921         setIntField(env,  rttResult, "tx_rate",              result.tx_rate.bitrate);
    922         setLongField(env, rttResult, "rtt_ns",               result.rtt);
    923         setLongField(env, rttResult, "rtt_sd_ns",            result.rtt_sd);
    924         setLongField(env, rttResult, "rtt_spread_ns",        result.rtt_spread);
    925         setIntField(env,  rttResult, "distance_cm",          result.distance);
    926         setIntField(env,  rttResult, "distance_sd_cm",       result.distance_sd);
    927         setIntField(env,  rttResult, "distance_spread_cm",   result.distance_spread);
    928 
    929         env->SetObjectArrayElement(rttResults, i, rttResult);
    930     }
    931 
    932     reportEvent(env, mCls, "onRttResults", "(I[Landroid/net/wifi/RttManager$RttResult;)V",
    933         id, rttResults);
    934 }
    935 
    936 const int MaxRttConfigs = 16;
    937 
    938 static jboolean android_net_wifi_requestRange(
    939         JNIEnv *env, jclass cls, jint iface, jint id, jobject params)  {
    940 
    941     wifi_interface_handle handle = getIfaceHandle(env, cls, iface);
    942     ALOGD("sending rtt request [%d] = %p", id, handle);
    943 
    944     wifi_rtt_config configs[MaxRttConfigs];
    945     memset(&configs, 0, sizeof(configs));
    946 
    947     int len = env->GetArrayLength((jobjectArray)params);
    948     if (len > MaxRttConfigs) {
    949         return false;
    950     }
    951 
    952     for (int i = 0; i < len; i++) {
    953 
    954         jobject param = env->GetObjectArrayElement((jobjectArray)params, i);
    955         if (param == NULL) {
    956             ALOGD("could not get element %d", i);
    957             continue;
    958         }
    959 
    960         wifi_rtt_config &config = configs[i];
    961 
    962         parseMacAddress(env, param, config.addr);
    963         config.type = (wifi_rtt_type)getIntField(env, param, "requestType");
    964         config.peer = (wifi_peer_type)getIntField(env, param, "deviceType");
    965         config.channel.center_freq = getIntField(env, param, "frequency");
    966         config.channel.width = (wifi_channel_width)getIntField(env, param, "channelWidth");
    967         config.num_samples_per_measurement = getIntField(env, param, "num_samples");
    968         config.num_retries_per_measurement = getIntField(env, param, "num_retries");
    969     }
    970 
    971     wifi_rtt_event_handler handler;
    972     handler.on_rtt_results = &onRttResults;
    973 
    974     return wifi_rtt_range_request(id, handle, len, configs, handler) == WIFI_SUCCESS;
    975 }
    976 
    977 static jboolean android_net_wifi_cancelRange(
    978         JNIEnv *env, jclass cls, jint iface, jint id, jobject params)  {
    979 
    980     wifi_interface_handle handle = getIfaceHandle(env, cls, iface);
    981     ALOGD("cancelling rtt request [%d] = %p", id, handle);
    982 
    983     mac_addr addrs[MaxRttConfigs];
    984     memset(&addrs, 0, sizeof(addrs));
    985 
    986     int len = env->GetArrayLength((jobjectArray)params);
    987     if (len > MaxRttConfigs) {
    988         return false;
    989     }
    990 
    991     for (int i = 0; i < len; i++) {
    992 
    993         jobject param = env->GetObjectArrayElement((jobjectArray)params, i);
    994         if (param == NULL) {
    995             ALOGD("could not get element %d", i);
    996             continue;
    997         }
    998 
    999         parseMacAddress(env, param, addrs[i]);
   1000     }
   1001 
   1002     return wifi_rtt_range_cancel(id, handle, len, addrs) == WIFI_SUCCESS;
   1003 }
   1004 
   1005 static jboolean android_net_wifi_setScanningMacOui(JNIEnv *env, jclass cls,
   1006         jint iface, jbyteArray param)  {
   1007 
   1008     wifi_interface_handle handle = getIfaceHandle(env, cls, iface);
   1009     ALOGD("setting scan oui %p", handle);
   1010 
   1011     static const unsigned oui_len = 3;          /* OUI is upper 3 bytes of mac_address */
   1012     int len = env->GetArrayLength(param);
   1013     if (len != oui_len) {
   1014         ALOGE("invalid oui length %d", len);
   1015         return false;
   1016     }
   1017 
   1018     jbyte* bytes = env->GetByteArrayElements(param, NULL);
   1019     if (bytes == NULL) {
   1020         ALOGE("failed to get array");
   1021         return false;
   1022     }
   1023 
   1024     return wifi_set_scanning_mac_oui(handle, (byte *)bytes) == WIFI_SUCCESS;
   1025 }
   1026 
   1027 static jintArray android_net_wifi_getValidChannels(JNIEnv *env, jclass cls,
   1028         jint iface, jint band)  {
   1029 
   1030     wifi_interface_handle handle = getIfaceHandle(env, cls, iface);
   1031     ALOGD("getting valid channels %p", handle);
   1032 
   1033     static const int MaxChannels = 64;
   1034     wifi_channel channels[64];
   1035     int num_channels = 0;
   1036     wifi_error result = wifi_get_valid_channels(handle, band, MaxChannels,
   1037             channels, &num_channels);
   1038 
   1039     if (result == WIFI_SUCCESS) {
   1040         jintArray channelArray = env->NewIntArray(num_channels);
   1041         if (channelArray == NULL) {
   1042             ALOGE("failed to allocate channel list");
   1043             return NULL;
   1044         }
   1045 
   1046         env->SetIntArrayRegion(channelArray, 0, num_channels, channels);
   1047         return channelArray;
   1048     } else {
   1049         ALOGE("failed to get channel list : %d", result);
   1050         return NULL;
   1051     }
   1052 }
   1053 
   1054 // ----------------------------------------------------------------------------
   1055 
   1056 /*
   1057  * JNI registration.
   1058  */
   1059 static JNINativeMethod gWifiMethods[] = {
   1060     /* name, signature, funcPtr */
   1061 
   1062     { "loadDriver", "()Z",  (void *)android_net_wifi_loadDriver },
   1063     { "isDriverLoaded", "()Z",  (void *)android_net_wifi_isDriverLoaded },
   1064     { "unloadDriver", "()Z",  (void *)android_net_wifi_unloadDriver },
   1065     { "startSupplicant", "(Z)Z",  (void *)android_net_wifi_startSupplicant },
   1066     { "killSupplicant", "(Z)Z",  (void *)android_net_wifi_killSupplicant },
   1067     { "connectToSupplicantNative", "()Z", (void *)android_net_wifi_connectToSupplicant },
   1068     { "closeSupplicantConnectionNative", "()V",
   1069             (void *)android_net_wifi_closeSupplicantConnection },
   1070     { "waitForEventNative", "()Ljava/lang/String;", (void*)android_net_wifi_waitForEvent },
   1071     { "doBooleanCommandNative", "(Ljava/lang/String;)Z", (void*)android_net_wifi_doBooleanCommand },
   1072     { "doIntCommandNative", "(Ljava/lang/String;)I", (void*)android_net_wifi_doIntCommand },
   1073     { "doStringCommandNative", "(Ljava/lang/String;)Ljava/lang/String;",
   1074             (void*) android_net_wifi_doStringCommand },
   1075     { "startHalNative", "()Z", (void*) android_net_wifi_startHal },
   1076     { "stopHalNative", "()V", (void*) android_net_wifi_stopHal },
   1077     { "waitForHalEventNative", "()V", (void*) android_net_wifi_waitForHalEvents },
   1078     { "getInterfacesNative", "()I", (void*) android_net_wifi_getInterfaces},
   1079     { "getInterfaceNameNative", "(I)Ljava/lang/String;", (void*) android_net_wifi_getInterfaceName},
   1080     { "getScanCapabilitiesNative", "(ILcom/android/server/wifi/WifiNative$ScanCapabilities;)Z",
   1081             (void *) android_net_wifi_getScanCapabilities},
   1082     { "startScanNative", "(IILcom/android/server/wifi/WifiNative$ScanSettings;)Z",
   1083             (void*) android_net_wifi_startScan},
   1084     { "stopScanNative", "(II)Z", (void*) android_net_wifi_stopScan},
   1085     { "getScanResultsNative", "(IZ)[Landroid/net/wifi/ScanResult;",
   1086             (void *) android_net_wifi_getScanResults},
   1087     { "setHotlistNative", "(IILandroid/net/wifi/WifiScanner$HotlistSettings;)Z",
   1088             (void*) android_net_wifi_setHotlist},
   1089     { "resetHotlistNative", "(II)Z", (void*) android_net_wifi_resetHotlist},
   1090     { "trackSignificantWifiChangeNative", "(IILandroid/net/wifi/WifiScanner$WifiChangeSettings;)Z",
   1091             (void*) android_net_wifi_trackSignificantWifiChange},
   1092     { "untrackSignificantWifiChangeNative", "(II)Z",
   1093             (void*) android_net_wifi_untrackSignificantWifiChange},
   1094     { "getWifiLinkLayerStatsNative", "(I)Landroid/net/wifi/WifiLinkLayerStats;",
   1095             (void*) android_net_wifi_getLinkLayerStats},
   1096     { "getSupportedFeatureSetNative", "(I)I",
   1097             (void*) android_net_wifi_getSupportedFeatures},
   1098     { "requestRangeNative", "(II[Landroid/net/wifi/RttManager$RttParams;)Z",
   1099             (void*) android_net_wifi_requestRange},
   1100     { "cancelRangeRequestNative", "(II[Landroid/net/wifi/RttManager$RttParams;)Z",
   1101             (void*) android_net_wifi_cancelRange},
   1102     { "setScanningMacOuiNative", "(I[B)Z", (void*) android_net_wifi_setScanningMacOui},
   1103     { "getChannelsForBandNative", "(II)[I", (void*) android_net_wifi_getValidChannels}
   1104 };
   1105 
   1106 int register_android_net_wifi_WifiNative(JNIEnv* env) {
   1107     return AndroidRuntime::registerNativeMethods(env,
   1108             "com/android/server/wifi/WifiNative", gWifiMethods, NELEM(gWifiMethods));
   1109 }
   1110 
   1111 
   1112 /* User to register native functions */
   1113 extern "C"
   1114 jint Java_com_android_server_wifi_WifiNative_registerNatives(JNIEnv* env, jclass clazz) {
   1115     return AndroidRuntime::registerNativeMethods(env,
   1116             "com/android/server/wifi/WifiNative", gWifiMethods, NELEM(gWifiMethods));
   1117 }
   1118 
   1119 }; // namespace android
   1120