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