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 
     26 #include "wifi.h"
     27 
     28 #define WIFI_PKG_NAME "android/net/wifi/WifiNative"
     29 #define BUF_SIZE 256
     30 
     31 //TODO: This file can be refactored to push a lot of the functionality to java
     32 //with just a few JNI calls - doBoolean/doInt/doString
     33 
     34 namespace android {
     35 
     36 static jboolean sScanModeActive = false;
     37 
     38 static int doCommand(const char *cmd, char *replybuf, int replybuflen)
     39 {
     40     size_t reply_len = replybuflen - 1;
     41 
     42     if (::wifi_command(cmd, replybuf, &reply_len) != 0)
     43         return -1;
     44     else {
     45         // Strip off trailing newline
     46         if (reply_len > 0 && replybuf[reply_len-1] == '\n')
     47             replybuf[reply_len-1] = '\0';
     48         else
     49             replybuf[reply_len] = '\0';
     50         return 0;
     51     }
     52 }
     53 
     54 static jint doIntCommand(const char* fmt, ...)
     55 {
     56     char buf[BUF_SIZE];
     57     va_list args;
     58     va_start(args, fmt);
     59     int byteCount = vsnprintf(buf, sizeof(buf), fmt, args);
     60     va_end(args);
     61     if (byteCount < 0 || byteCount >= BUF_SIZE) {
     62         return -1;
     63     }
     64     char reply[BUF_SIZE];
     65     if (doCommand(buf, reply, sizeof(reply)) != 0) {
     66         return -1;
     67     }
     68     return static_cast<jint>(atoi(reply));
     69 }
     70 
     71 static jboolean doBooleanCommand(const char* expect, const char* fmt, ...)
     72 {
     73     char buf[BUF_SIZE];
     74     va_list args;
     75     va_start(args, fmt);
     76     int byteCount = vsnprintf(buf, sizeof(buf), fmt, args);
     77     va_end(args);
     78     if (byteCount < 0 || byteCount >= BUF_SIZE) {
     79         return JNI_FALSE;
     80     }
     81     char reply[BUF_SIZE];
     82     if (doCommand(buf, reply, sizeof(reply)) != 0) {
     83         return JNI_FALSE;
     84     }
     85     return (strcmp(reply, expect) == 0);
     86 }
     87 
     88 // Send a command to the supplicant, and return the reply as a String
     89 static jstring doStringCommand(JNIEnv* env, const char* fmt, ...) {
     90     char buf[BUF_SIZE];
     91     va_list args;
     92     va_start(args, fmt);
     93     int byteCount = vsnprintf(buf, sizeof(buf), fmt, args);
     94     va_end(args);
     95     if (byteCount < 0 || byteCount >= BUF_SIZE) {
     96         return NULL;
     97     }
     98     char reply[4096];
     99     if (doCommand(buf, reply, sizeof(reply)) != 0) {
    100         return NULL;
    101     }
    102     // TODO: why not just NewStringUTF?
    103     String16 str((char *)reply);
    104     return env->NewString((const jchar *)str.string(), str.size());
    105 }
    106 
    107 static jboolean android_net_wifi_isDriverLoaded(JNIEnv* env, jobject)
    108 {
    109     return (jboolean)(::is_wifi_driver_loaded() == 1);
    110 }
    111 
    112 static jboolean android_net_wifi_loadDriver(JNIEnv* env, jobject)
    113 {
    114     return (jboolean)(::wifi_load_driver() == 0);
    115 }
    116 
    117 static jboolean android_net_wifi_unloadDriver(JNIEnv* env, jobject)
    118 {
    119     return (jboolean)(::wifi_unload_driver() == 0);
    120 }
    121 
    122 static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject)
    123 {
    124     return (jboolean)(::wifi_start_supplicant() == 0);
    125 }
    126 
    127 static jboolean android_net_wifi_startP2pSupplicant(JNIEnv* env, jobject)
    128 {
    129     return (jboolean)(::wifi_start_p2p_supplicant() == 0);
    130 }
    131 
    132 static jboolean android_net_wifi_stopSupplicant(JNIEnv* env, jobject)
    133 {
    134     return doBooleanCommand("OK", "TERMINATE");
    135 }
    136 
    137 static jboolean android_net_wifi_killSupplicant(JNIEnv* env, jobject)
    138 {
    139     return (jboolean)(::wifi_stop_supplicant() == 0);
    140 }
    141 
    142 static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jobject)
    143 {
    144     return (jboolean)(::wifi_connect_to_supplicant() == 0);
    145 }
    146 
    147 static void android_net_wifi_closeSupplicantConnection(JNIEnv* env, jobject)
    148 {
    149     ::wifi_close_supplicant_connection();
    150 }
    151 
    152 static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject)
    153 {
    154     char buf[BUF_SIZE];
    155 
    156     int nread = ::wifi_wait_for_event(buf, sizeof buf);
    157     if (nread > 0) {
    158         return env->NewStringUTF(buf);
    159     } else {
    160         return NULL;
    161     }
    162 }
    163 
    164 static jstring android_net_wifi_listNetworksCommand(JNIEnv* env, jobject)
    165 {
    166     return doStringCommand(env, "LIST_NETWORKS");
    167 }
    168 
    169 static jint android_net_wifi_addNetworkCommand(JNIEnv* env, jobject)
    170 {
    171     return doIntCommand("ADD_NETWORK");
    172 }
    173 
    174 static jboolean android_net_wifi_wpsPbcCommand(JNIEnv* env, jobject, jstring javaBssid)
    175 {
    176     ScopedUtfChars bssid(env, javaBssid);
    177     if (bssid.c_str() == NULL) {
    178         return JNI_FALSE;
    179     }
    180     return doBooleanCommand("OK", "WPS_PBC %s", bssid.c_str());
    181 }
    182 
    183 static jboolean android_net_wifi_wpsPinFromAccessPointCommand(JNIEnv* env, jobject,
    184         jstring javaBssid, jstring javaApPin)
    185 {
    186     ScopedUtfChars bssid(env, javaBssid);
    187     if (bssid.c_str() == NULL) {
    188         return JNI_FALSE;
    189     }
    190     ScopedUtfChars apPin(env, javaApPin);
    191     if (apPin.c_str() == NULL) {
    192         return JNI_FALSE;
    193     }
    194     return doBooleanCommand("OK", "WPS_REG %s %s", bssid.c_str(), apPin.c_str());
    195 }
    196 
    197 static jstring android_net_wifi_wpsPinFromDeviceCommand(JNIEnv* env, jobject, jstring javaBssid)
    198 {
    199     ScopedUtfChars bssid(env, javaBssid);
    200     if (bssid.c_str() == NULL) {
    201         return NULL;
    202     }
    203     return doStringCommand(env, "WPS_PIN %s", bssid.c_str());
    204 }
    205 
    206 static jboolean android_net_wifi_setCountryCodeCommand(JNIEnv* env, jobject, jstring javaCountry)
    207 {
    208     ScopedUtfChars country(env, javaCountry);
    209     if (country.c_str() == NULL) {
    210         return JNI_FALSE;
    211     }
    212     return doBooleanCommand("OK", "DRIVER COUNTRY %s", country.c_str());
    213 }
    214 
    215 static jboolean android_net_wifi_setNetworkVariableCommand(JNIEnv* env,
    216                                                            jobject,
    217                                                            jint netId,
    218                                                            jstring javaName,
    219                                                            jstring javaValue)
    220 {
    221     ScopedUtfChars name(env, javaName);
    222     if (name.c_str() == NULL) {
    223         return JNI_FALSE;
    224     }
    225     ScopedUtfChars value(env, javaValue);
    226     if (value.c_str() == NULL) {
    227         return JNI_FALSE;
    228     }
    229     return doBooleanCommand("OK", "SET_NETWORK %d %s %s", netId, name.c_str(), value.c_str());
    230 }
    231 
    232 static jstring android_net_wifi_getNetworkVariableCommand(JNIEnv* env,
    233                                                           jobject,
    234                                                           jint netId,
    235                                                           jstring javaName)
    236 {
    237     ScopedUtfChars name(env, javaName);
    238     if (name.c_str() == NULL) {
    239         return NULL;
    240     }
    241     return doStringCommand(env, "GET_NETWORK %d %s", netId, name.c_str());
    242 }
    243 
    244 static jboolean android_net_wifi_removeNetworkCommand(JNIEnv* env, jobject, jint netId)
    245 {
    246     return doBooleanCommand("OK", "REMOVE_NETWORK %d", netId);
    247 }
    248 
    249 static jboolean android_net_wifi_enableNetworkCommand(JNIEnv* env,
    250                                                   jobject,
    251                                                   jint netId,
    252                                                   jboolean disableOthers)
    253 {
    254     return doBooleanCommand("OK", "%s_NETWORK %d", disableOthers ? "SELECT" : "ENABLE", netId);
    255 }
    256 
    257 static jboolean android_net_wifi_disableNetworkCommand(JNIEnv* env, jobject, jint netId)
    258 {
    259     return doBooleanCommand("OK", "DISABLE_NETWORK %d", netId);
    260 }
    261 
    262 static jstring android_net_wifi_statusCommand(JNIEnv* env, jobject)
    263 {
    264     return doStringCommand(env, "STATUS");
    265 }
    266 
    267 static jboolean android_net_wifi_pingCommand(JNIEnv* env, jobject)
    268 {
    269     return doBooleanCommand("PONG", "PING");
    270 }
    271 
    272 static jstring android_net_wifi_scanResultsCommand(JNIEnv* env, jobject)
    273 {
    274     return doStringCommand(env, "SCAN_RESULTS");
    275 }
    276 
    277 static jboolean android_net_wifi_disconnectCommand(JNIEnv* env, jobject)
    278 {
    279     return doBooleanCommand("OK", "DISCONNECT");
    280 }
    281 
    282 static jboolean android_net_wifi_reconnectCommand(JNIEnv* env, jobject)
    283 {
    284     return doBooleanCommand("OK", "RECONNECT");
    285 }
    286 static jboolean android_net_wifi_reassociateCommand(JNIEnv* env, jobject)
    287 {
    288     return doBooleanCommand("OK", "REASSOCIATE");
    289 }
    290 
    291 static jboolean doSetScanMode(jboolean setActive)
    292 {
    293     return doBooleanCommand("OK", (setActive ? "DRIVER SCAN-ACTIVE" : "DRIVER SCAN-PASSIVE"));
    294 }
    295 
    296 static jboolean android_net_wifi_scanCommand(JNIEnv* env, jobject, jboolean forceActive)
    297 {
    298     jboolean result;
    299 
    300     // Ignore any error from setting the scan mode.
    301     // The scan will still work.
    302     if (forceActive && !sScanModeActive)
    303         doSetScanMode(true);
    304     result = doBooleanCommand("OK", "SCAN");
    305     if (forceActive && !sScanModeActive)
    306         doSetScanMode(sScanModeActive);
    307     return result;
    308 }
    309 
    310 static jboolean android_net_wifi_setScanModeCommand(JNIEnv* env, jobject, jboolean setActive)
    311 {
    312     sScanModeActive = setActive;
    313     return doSetScanMode(setActive);
    314 }
    315 
    316 static jboolean android_net_wifi_startDriverCommand(JNIEnv* env, jobject)
    317 {
    318     return doBooleanCommand("OK", "DRIVER START");
    319 }
    320 
    321 static jboolean android_net_wifi_stopDriverCommand(JNIEnv* env, jobject)
    322 {
    323     return doBooleanCommand("OK", "DRIVER STOP");
    324 }
    325 
    326 /*
    327     Multicast filtering rules work as follows:
    328 
    329     The driver can filter multicast (v4 and/or v6) and broadcast packets when in
    330     a power optimized mode (typically when screen goes off).
    331 
    332     In order to prevent the driver from filtering the multicast/broadcast packets, we have to
    333     add a DRIVER RXFILTER-ADD rule followed by DRIVER RXFILTER-START to make the rule effective
    334 
    335     DRIVER RXFILTER-ADD Num
    336         where Num = 0 - Unicast, 1 - Broadcast, 2 - Mutil4 or 3 - Multi6
    337 
    338     and DRIVER RXFILTER-START
    339 
    340     In order to stop the usage of these rules, we do
    341 
    342     DRIVER RXFILTER-STOP
    343     DRIVER RXFILTER-REMOVE Num
    344         where Num is as described for RXFILTER-ADD
    345 
    346     The  SETSUSPENDOPT driver command overrides the filtering rules
    347 */
    348 
    349 static jboolean android_net_wifi_startMultiV4Filtering(JNIEnv* env, jobject)
    350 {
    351     return doBooleanCommand("OK", "DRIVER RXFILTER-STOP")
    352             && doBooleanCommand("OK", "DRIVER RXFILTER-REMOVE 2")
    353             && doBooleanCommand("OK", "DRIVER RXFILTER-START");
    354 }
    355 
    356 static jboolean android_net_wifi_stopMultiV4Filtering(JNIEnv* env, jobject)
    357 {
    358     return doBooleanCommand("OK", "DRIVER RXFILTER-ADD 2")
    359             && doBooleanCommand("OK", "DRIVER RXFILTER-START");
    360 }
    361 
    362 static jboolean android_net_wifi_startMultiV6Filtering(JNIEnv* env, jobject)
    363 {
    364     return doBooleanCommand("OK", "DRIVER RXFILTER-STOP")
    365             && doBooleanCommand("OK", "DRIVER RXFILTER-REMOVE 3")
    366             && doBooleanCommand("OK", "DRIVER RXFILTER-START");
    367 }
    368 
    369 static jboolean android_net_wifi_stopMultiV6Filtering(JNIEnv* env, jobject)
    370 {
    371     return doBooleanCommand("OK", "DRIVER RXFILTER-ADD 3")
    372         && doBooleanCommand("OK", "DRIVER RXFILTER-START");
    373 }
    374 
    375 
    376 static jint android_net_wifi_getRssiHelper(const char *cmd)
    377 {
    378     char reply[BUF_SIZE];
    379     int rssi = -200;
    380 
    381     if (doCommand(cmd, reply, sizeof(reply)) != 0) {
    382         return (jint)-1;
    383     }
    384 
    385     // reply comes back in the form "<SSID> rssi XX" where XX is the
    386     // number we're interested in.  if we're associating, it returns "OK".
    387     // beware - <SSID> can contain spaces.
    388     if (strcmp(reply, "OK") != 0) {
    389         // beware of trailing spaces
    390         char* end = reply + strlen(reply);
    391         while (end > reply && end[-1] == ' ') {
    392             end--;
    393         }
    394         *end = 0;
    395 
    396         char* lastSpace = strrchr(reply, ' ');
    397         // lastSpace should be preceded by "rssi" and followed by the value
    398         if (lastSpace && !strncasecmp(lastSpace - 4, "rssi", 4)) {
    399             sscanf(lastSpace + 1, "%d", &rssi);
    400         }
    401     }
    402     return (jint)rssi;
    403 }
    404 
    405 static jstring android_net_wifi_getMacAddressCommand(JNIEnv* env, jobject)
    406 {
    407     char reply[BUF_SIZE];
    408     char buf[BUF_SIZE];
    409 
    410     if (doCommand("DRIVER MACADDR", reply, sizeof(reply)) != 0) {
    411         return NULL;
    412     }
    413     // reply comes back in the form "Macaddr = XX.XX.XX.XX.XX.XX" where XX
    414     // is the part of the string we're interested in.
    415     if (sscanf(reply, "%*s = %255s", buf) == 1) {
    416         return env->NewStringUTF(buf);
    417     }
    418     return NULL;
    419 }
    420 
    421 static jboolean android_net_wifi_setPowerModeCommand(JNIEnv* env, jobject, jint mode)
    422 {
    423     return doBooleanCommand("OK", "DRIVER POWERMODE %d", mode);
    424 }
    425 
    426 static jint android_net_wifi_getPowerModeCommand(JNIEnv* env, jobject)
    427 {
    428     char reply[BUF_SIZE];
    429     int power;
    430 
    431     if (doCommand("DRIVER GETPOWER", reply, sizeof(reply)) != 0) {
    432         return (jint)-1;
    433     }
    434     // reply comes back in the form "powermode = XX" where XX is the
    435     // number we're interested in.
    436     if (sscanf(reply, "%*s = %u", &power) != 1) {
    437         return (jint)-1;
    438     }
    439     return (jint)power;
    440 }
    441 
    442 static jboolean android_net_wifi_setBandCommand(JNIEnv* env, jobject, jint band)
    443 {
    444     return doBooleanCommand("OK", "DRIVER SETBAND %d", band);
    445 }
    446 
    447 static jint android_net_wifi_getBandCommand(JNIEnv* env, jobject)
    448 {
    449     char reply[25];
    450     int band;
    451 
    452     if (doCommand("DRIVER GETBAND", reply, sizeof(reply)) != 0) {
    453         return (jint)-1;
    454     }
    455     // reply comes back in the form "Band X" where X is the
    456     // number we're interested in.
    457     sscanf(reply, "%*s %u", &band);
    458     return (jint)band;
    459 }
    460 
    461 static jboolean android_net_wifi_setBluetoothCoexistenceModeCommand(JNIEnv* env, jobject, jint mode)
    462 {
    463     return doBooleanCommand("OK", "DRIVER BTCOEXMODE %d", mode);
    464 }
    465 
    466 static jboolean android_net_wifi_setBluetoothCoexistenceScanModeCommand(JNIEnv* env, jobject, jboolean setCoexScanMode)
    467 {
    468     return doBooleanCommand("OK", "DRIVER BTCOEXSCAN-%s", setCoexScanMode ? "START" : "STOP");
    469 }
    470 
    471 static jboolean android_net_wifi_saveConfigCommand(JNIEnv* env, jobject)
    472 {
    473     // Make sure we never write out a value for AP_SCAN other than 1
    474     (void)doBooleanCommand("OK", "AP_SCAN 1");
    475     return doBooleanCommand("OK", "SAVE_CONFIG");
    476 }
    477 
    478 static jboolean android_net_wifi_reloadConfigCommand(JNIEnv* env, jobject)
    479 {
    480     return doBooleanCommand("OK", "RECONFIGURE");
    481 }
    482 
    483 static jboolean android_net_wifi_setScanResultHandlingCommand(JNIEnv* env, jobject, jint mode)
    484 {
    485     return doBooleanCommand("OK", "AP_SCAN %d", mode);
    486 }
    487 
    488 static jboolean android_net_wifi_addToBlacklistCommand(JNIEnv* env, jobject, jstring javaBssid)
    489 {
    490     ScopedUtfChars bssid(env, javaBssid);
    491     if (bssid.c_str() == NULL) {
    492         return JNI_FALSE;
    493     }
    494     return doBooleanCommand("OK", "BLACKLIST %s", bssid.c_str());
    495 }
    496 
    497 static jboolean android_net_wifi_clearBlacklistCommand(JNIEnv* env, jobject)
    498 {
    499     return doBooleanCommand("OK", "BLACKLIST clear");
    500 }
    501 
    502 static jboolean android_net_wifi_setSuspendOptimizationsCommand(JNIEnv* env, jobject, jboolean enabled)
    503 {
    504     return doBooleanCommand("OK", "DRIVER SETSUSPENDOPT %d", enabled ? 0 : 1);
    505 }
    506 
    507 static void android_net_wifi_enableBackgroundScanCommand(JNIEnv* env, jobject, jboolean enable)
    508 {
    509     //Note: BGSCAN-START and BGSCAN-STOP are documented in core/res/res/values/config.xml
    510     //and will need an update if the names are changed
    511     if (enable) {
    512         doBooleanCommand("OK", "DRIVER BGSCAN-START");
    513     } else {
    514         doBooleanCommand("OK", "DRIVER BGSCAN-STOP");
    515     }
    516 }
    517 
    518 static void android_net_wifi_setScanIntervalCommand(JNIEnv* env, jobject, jint scanInterval)
    519 {
    520     doBooleanCommand("OK", "SCAN_INTERVAL %d", scanInterval);
    521 }
    522 
    523 
    524 static jboolean android_net_wifi_doBooleanCommand(JNIEnv* env, jobject, jstring javaCommand)
    525 {
    526     ScopedUtfChars command(env, javaCommand);
    527     if (command.c_str() == NULL) {
    528         return JNI_FALSE;
    529     }
    530     return doBooleanCommand("OK", "%s", command.c_str());
    531 }
    532 
    533 static jint android_net_wifi_doIntCommand(JNIEnv* env, jobject, jstring javaCommand)
    534 {
    535     ScopedUtfChars command(env, javaCommand);
    536     if (command.c_str() == NULL) {
    537         return -1;
    538     }
    539     return doIntCommand("%s", command.c_str());
    540 }
    541 
    542 static jstring android_net_wifi_doStringCommand(JNIEnv* env, jobject, jstring javaCommand)
    543 {
    544     ScopedUtfChars command(env, javaCommand);
    545     if (command.c_str() == NULL) {
    546         return NULL;
    547     }
    548     return doStringCommand(env, "%s", command.c_str());
    549 }
    550 
    551 
    552 
    553 // ----------------------------------------------------------------------------
    554 
    555 /*
    556  * JNI registration.
    557  */
    558 static JNINativeMethod gWifiMethods[] = {
    559     /* name, signature, funcPtr */
    560 
    561     { "loadDriver", "()Z",  (void *)android_net_wifi_loadDriver },
    562     { "isDriverLoaded", "()Z",  (void *)android_net_wifi_isDriverLoaded},
    563     { "unloadDriver", "()Z",  (void *)android_net_wifi_unloadDriver },
    564     { "startSupplicant", "()Z",  (void *)android_net_wifi_startSupplicant },
    565     { "startP2pSupplicant", "()Z",  (void *)android_net_wifi_startP2pSupplicant },
    566     { "stopSupplicant", "()Z", (void*) android_net_wifi_stopSupplicant },
    567     { "killSupplicant", "()Z",  (void *)android_net_wifi_killSupplicant },
    568     { "connectToSupplicant", "()Z",  (void *)android_net_wifi_connectToSupplicant },
    569     { "closeSupplicantConnection", "()V",  (void *)android_net_wifi_closeSupplicantConnection },
    570 
    571     { "listNetworksCommand", "()Ljava/lang/String;",
    572         (void*) android_net_wifi_listNetworksCommand },
    573     { "addNetworkCommand", "()I", (void*) android_net_wifi_addNetworkCommand },
    574     { "setNetworkVariableCommand", "(ILjava/lang/String;Ljava/lang/String;)Z",
    575         (void*) android_net_wifi_setNetworkVariableCommand },
    576     { "getNetworkVariableCommand", "(ILjava/lang/String;)Ljava/lang/String;",
    577         (void*) android_net_wifi_getNetworkVariableCommand },
    578     { "removeNetworkCommand", "(I)Z", (void*) android_net_wifi_removeNetworkCommand },
    579     { "enableNetworkCommand", "(IZ)Z", (void*) android_net_wifi_enableNetworkCommand },
    580     { "disableNetworkCommand", "(I)Z", (void*) android_net_wifi_disableNetworkCommand },
    581     { "waitForEvent", "()Ljava/lang/String;", (void*) android_net_wifi_waitForEvent },
    582     { "statusCommand", "()Ljava/lang/String;", (void*) android_net_wifi_statusCommand },
    583     { "scanResultsCommand", "()Ljava/lang/String;", (void*) android_net_wifi_scanResultsCommand },
    584     { "pingCommand", "()Z",  (void *)android_net_wifi_pingCommand },
    585     { "disconnectCommand", "()Z",  (void *)android_net_wifi_disconnectCommand },
    586     { "reconnectCommand", "()Z",  (void *)android_net_wifi_reconnectCommand },
    587     { "reassociateCommand", "()Z",  (void *)android_net_wifi_reassociateCommand },
    588     { "scanCommand", "(Z)Z", (void*) android_net_wifi_scanCommand },
    589     { "setScanModeCommand", "(Z)Z", (void*) android_net_wifi_setScanModeCommand },
    590     { "startDriverCommand", "()Z", (void*) android_net_wifi_startDriverCommand },
    591     { "stopDriverCommand", "()Z", (void*) android_net_wifi_stopDriverCommand },
    592     { "startFilteringMulticastV4Packets", "()Z", (void*) android_net_wifi_startMultiV4Filtering},
    593     { "stopFilteringMulticastV4Packets", "()Z", (void*) android_net_wifi_stopMultiV4Filtering},
    594     { "startFilteringMulticastV6Packets", "()Z", (void*) android_net_wifi_startMultiV6Filtering},
    595     { "stopFilteringMulticastV6Packets", "()Z", (void*) android_net_wifi_stopMultiV6Filtering},
    596     { "setPowerModeCommand", "(I)Z", (void*) android_net_wifi_setPowerModeCommand },
    597     { "getPowerModeCommand", "()I", (void*) android_net_wifi_getPowerModeCommand },
    598     { "setBandCommand", "(I)Z", (void*) android_net_wifi_setBandCommand},
    599     { "getBandCommand", "()I", (void*) android_net_wifi_getBandCommand},
    600     { "setBluetoothCoexistenceModeCommand", "(I)Z",
    601     		(void*) android_net_wifi_setBluetoothCoexistenceModeCommand },
    602     { "setBluetoothCoexistenceScanModeCommand", "(Z)Z",
    603     		(void*) android_net_wifi_setBluetoothCoexistenceScanModeCommand },
    604     { "getMacAddressCommand", "()Ljava/lang/String;", (void*) android_net_wifi_getMacAddressCommand },
    605     { "saveConfigCommand", "()Z", (void*) android_net_wifi_saveConfigCommand },
    606     { "reloadConfigCommand", "()Z", (void*) android_net_wifi_reloadConfigCommand },
    607     { "setScanResultHandlingCommand", "(I)Z", (void*) android_net_wifi_setScanResultHandlingCommand },
    608     { "addToBlacklistCommand", "(Ljava/lang/String;)Z", (void*) android_net_wifi_addToBlacklistCommand },
    609     { "clearBlacklistCommand", "()Z", (void*) android_net_wifi_clearBlacklistCommand },
    610     { "startWpsPbcCommand", "(Ljava/lang/String;)Z", (void*) android_net_wifi_wpsPbcCommand },
    611     { "startWpsWithPinFromAccessPointCommand", "(Ljava/lang/String;Ljava/lang/String;)Z",
    612         (void*) android_net_wifi_wpsPinFromAccessPointCommand },
    613     { "startWpsWithPinFromDeviceCommand", "(Ljava/lang/String;)Ljava/lang/String;",
    614         (void*) android_net_wifi_wpsPinFromDeviceCommand },
    615     { "setSuspendOptimizationsCommand", "(Z)Z",
    616         (void*) android_net_wifi_setSuspendOptimizationsCommand},
    617     { "setCountryCodeCommand", "(Ljava/lang/String;)Z",
    618         (void*) android_net_wifi_setCountryCodeCommand},
    619     { "enableBackgroundScanCommand", "(Z)V", (void*) android_net_wifi_enableBackgroundScanCommand},
    620     { "setScanIntervalCommand", "(I)V", (void*) android_net_wifi_setScanIntervalCommand},
    621     { "doBooleanCommand", "(Ljava/lang/String;)Z", (void*) android_net_wifi_doBooleanCommand},
    622     { "doIntCommand", "(Ljava/lang/String;)I", (void*) android_net_wifi_doIntCommand},
    623     { "doStringCommand", "(Ljava/lang/String;)Ljava/lang/String;", (void*) android_net_wifi_doStringCommand},
    624 };
    625 
    626 int register_android_net_wifi_WifiManager(JNIEnv* env)
    627 {
    628     return AndroidRuntime::registerNativeMethods(env,
    629             WIFI_PKG_NAME, gWifiMethods, NELEM(gWifiMethods));
    630 }
    631 
    632 }; // namespace android
    633