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