android_net_wifi_Wifi.cpp revision 921df5cbc44c00abe85f04093afe7692e73d490a
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_startP2pSupplicant(JNIEnv* env, jobject)
128{
129    return (jboolean)(::wifi_start_p2p_supplicant() == 0);
130}
131
132static jboolean android_net_wifi_stopSupplicant(JNIEnv* env, jobject)
133{
134    return doBooleanCommand("OK", "TERMINATE");
135}
136
137static jboolean android_net_wifi_killSupplicant(JNIEnv* env, jobject)
138{
139    return (jboolean)(::wifi_stop_supplicant() == 0);
140}
141
142static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jobject)
143{
144    return (jboolean)(::wifi_connect_to_supplicant() == 0);
145}
146
147static void android_net_wifi_closeSupplicantConnection(JNIEnv* env, jobject)
148{
149    ::wifi_close_supplicant_connection();
150}
151
152static 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
164static jstring android_net_wifi_listNetworksCommand(JNIEnv* env, jobject)
165{
166    return doStringCommand(env, "LIST_NETWORKS");
167}
168
169static jint android_net_wifi_addNetworkCommand(JNIEnv* env, jobject)
170{
171    return doIntCommand("ADD_NETWORK");
172}
173
174static 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
183static 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
197static 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
206static 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
215static 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
232static 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
244static jboolean android_net_wifi_removeNetworkCommand(JNIEnv* env, jobject, jint netId)
245{
246    return doBooleanCommand("OK", "REMOVE_NETWORK %d", netId);
247}
248
249static 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
257static jboolean android_net_wifi_disableNetworkCommand(JNIEnv* env, jobject, jint netId)
258{
259    return doBooleanCommand("OK", "DISABLE_NETWORK %d", netId);
260}
261
262static jstring android_net_wifi_statusCommand(JNIEnv* env, jobject)
263{
264    return doStringCommand(env, "STATUS");
265}
266
267static jboolean android_net_wifi_pingCommand(JNIEnv* env, jobject)
268{
269    return doBooleanCommand("PONG", "PING");
270}
271
272static jstring android_net_wifi_scanResultsCommand(JNIEnv* env, jobject)
273{
274    return doStringCommand(env, "SCAN_RESULTS");
275}
276
277static jboolean android_net_wifi_disconnectCommand(JNIEnv* env, jobject)
278{
279    return doBooleanCommand("OK", "DISCONNECT");
280}
281
282static jboolean android_net_wifi_reconnectCommand(JNIEnv* env, jobject)
283{
284    return doBooleanCommand("OK", "RECONNECT");
285}
286static jboolean android_net_wifi_reassociateCommand(JNIEnv* env, jobject)
287{
288    return doBooleanCommand("OK", "REASSOCIATE");
289}
290
291static jboolean doSetScanMode(jboolean setActive)
292{
293    return doBooleanCommand("OK", (setActive ? "DRIVER SCAN-ACTIVE" : "DRIVER SCAN-PASSIVE"));
294}
295
296static 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
310static jboolean android_net_wifi_setScanModeCommand(JNIEnv* env, jobject, jboolean setActive)
311{
312    sScanModeActive = setActive;
313    return doSetScanMode(setActive);
314}
315
316static jboolean android_net_wifi_startDriverCommand(JNIEnv* env, jobject)
317{
318    return doBooleanCommand("OK", "DRIVER START");
319}
320
321static 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
349static 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
356static 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
362static 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
369static 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
376static 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
405static 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
421static jboolean android_net_wifi_setPowerModeCommand(JNIEnv* env, jobject, jint mode)
422{
423    return doBooleanCommand("OK", "DRIVER POWERMODE %d", mode);
424}
425
426static 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
442static jboolean android_net_wifi_setBandCommand(JNIEnv* env, jobject, jint band)
443{
444    return doBooleanCommand("OK", "DRIVER SETBAND %d", band);
445}
446
447static 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
461static jboolean android_net_wifi_setBluetoothCoexistenceModeCommand(JNIEnv* env, jobject, jint mode)
462{
463    return doBooleanCommand("OK", "DRIVER BTCOEXMODE %d", mode);
464}
465
466static jboolean android_net_wifi_setBluetoothCoexistenceScanModeCommand(JNIEnv* env, jobject, jboolean setCoexScanMode)
467{
468    return doBooleanCommand("OK", "DRIVER BTCOEXSCAN-%s", setCoexScanMode ? "START" : "STOP");
469}
470
471static 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
478static jboolean android_net_wifi_reloadConfigCommand(JNIEnv* env, jobject)
479{
480    return doBooleanCommand("OK", "RECONFIGURE");
481}
482
483static jboolean android_net_wifi_setScanResultHandlingCommand(JNIEnv* env, jobject, jint mode)
484{
485    return doBooleanCommand("OK", "AP_SCAN %d", mode);
486}
487
488static 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
497static jboolean android_net_wifi_clearBlacklistCommand(JNIEnv* env, jobject)
498{
499    return doBooleanCommand("OK", "BLACKLIST clear");
500}
501
502static jboolean android_net_wifi_setSuspendOptimizationsCommand(JNIEnv* env, jobject, jboolean enabled)
503{
504    return doBooleanCommand("OK", "DRIVER SETSUSPENDOPT %d", enabled ? 0 : 1);
505}
506
507static 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
518static void android_net_wifi_setScanIntervalCommand(JNIEnv* env, jobject, jint scanInterval)
519{
520    doBooleanCommand("OK", "SCAN_INTERVAL %d", scanInterval);
521}
522
523
524static 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
533static 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
542static 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 */
558static 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
626int 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