1 /* 2 * Copyright (C) 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 package android.net.wifi; 18 19 import android.net.NetworkInfo; 20 import android.net.wifi.p2p.WifiP2pConfig; 21 import android.net.wifi.p2p.WifiP2pDevice; 22 import android.net.wifi.p2p.WifiP2pGroup; 23 import android.net.wifi.StateChangeResult; 24 import android.os.Message; 25 import android.util.Log; 26 27 28 import com.android.internal.util.Protocol; 29 import com.android.internal.util.StateMachine; 30 31 import java.util.regex.Pattern; 32 import java.util.regex.Matcher; 33 34 /** 35 * Listens for events from the wpa_supplicant server, and passes them on 36 * to the {@link StateMachine} for handling. Runs in its own thread. 37 * 38 * @hide 39 */ 40 public class WifiMonitor { 41 42 private static final String TAG = "WifiMonitor"; 43 44 /** Events we receive from the supplicant daemon */ 45 46 private static final int CONNECTED = 1; 47 private static final int DISCONNECTED = 2; 48 private static final int STATE_CHANGE = 3; 49 private static final int SCAN_RESULTS = 4; 50 private static final int LINK_SPEED = 5; 51 private static final int TERMINATING = 6; 52 private static final int DRIVER_STATE = 7; 53 private static final int EAP_FAILURE = 8; 54 private static final int UNKNOWN = 9; 55 56 /** All events coming from the supplicant start with this prefix */ 57 private static final String EVENT_PREFIX_STR = "CTRL-EVENT-"; 58 private static final int EVENT_PREFIX_LEN_STR = EVENT_PREFIX_STR.length(); 59 60 /** All WPA events coming from the supplicant start with this prefix */ 61 private static final String WPA_EVENT_PREFIX_STR = "WPA:"; 62 private static final String PASSWORD_MAY_BE_INCORRECT_STR = 63 "pre-shared key may be incorrect"; 64 65 /* WPS events */ 66 private static final String WPS_OVERLAP_STR = "WPS-OVERLAP-DETECTED"; 67 68 /** 69 * Names of events from wpa_supplicant (minus the prefix). In the 70 * format descriptions, * "<code>x</code>" 71 * designates a dynamic value that needs to be parsed out from the event 72 * string 73 */ 74 /** 75 * <pre> 76 * CTRL-EVENT-CONNECTED - Connection to xx:xx:xx:xx:xx:xx completed 77 * </pre> 78 * <code>xx:xx:xx:xx:xx:xx</code> is the BSSID of the associated access point 79 */ 80 private static final String CONNECTED_STR = "CONNECTED"; 81 /** 82 * <pre> 83 * CTRL-EVENT-DISCONNECTED - Disconnect event - remove keys 84 * </pre> 85 */ 86 private static final String DISCONNECTED_STR = "DISCONNECTED"; 87 /** 88 * <pre> 89 * CTRL-EVENT-STATE-CHANGE x 90 * </pre> 91 * <code>x</code> is the numerical value of the new state. 92 */ 93 private static final String STATE_CHANGE_STR = "STATE-CHANGE"; 94 /** 95 * <pre> 96 * CTRL-EVENT-SCAN-RESULTS ready 97 * </pre> 98 */ 99 private static final String SCAN_RESULTS_STR = "SCAN-RESULTS"; 100 101 /** 102 * <pre> 103 * CTRL-EVENT-LINK-SPEED x Mb/s 104 * </pre> 105 * {@code x} is the link speed in Mb/sec. 106 */ 107 private static final String LINK_SPEED_STR = "LINK-SPEED"; 108 /** 109 * <pre> 110 * CTRL-EVENT-TERMINATING - signal x 111 * </pre> 112 * <code>x</code> is the signal that caused termination. 113 */ 114 private static final String TERMINATING_STR = "TERMINATING"; 115 /** 116 * <pre> 117 * CTRL-EVENT-DRIVER-STATE state 118 * </pre> 119 * <code>state</code> can be HANGED 120 */ 121 private static final String DRIVER_STATE_STR = "DRIVER-STATE"; 122 /** 123 * <pre> 124 * CTRL-EVENT-EAP-FAILURE EAP authentication failed 125 * </pre> 126 */ 127 private static final String EAP_FAILURE_STR = "EAP-FAILURE"; 128 129 /** 130 * This indicates an authentication failure on EAP FAILURE event 131 */ 132 private static final String EAP_AUTH_FAILURE_STR = "EAP authentication failed"; 133 134 /** 135 * Regex pattern for extracting an Ethernet-style MAC address from a string. 136 * Matches a strings like the following:<pre> 137 * CTRL-EVENT-CONNECTED - Connection to 00:1e:58:ec:d5:6d completed (reauth) [id=1 id_str=]</pre> 138 */ 139 private static Pattern mConnectedEventPattern = 140 Pattern.compile("((?:[0-9a-f]{2}:){5}[0-9a-f]{2}) .* \\[id=([0-9]+) "); 141 142 /** P2P events */ 143 private static final String P2P_EVENT_PREFIX_STR = "P2P"; 144 145 /* P2P-DEVICE-FOUND fa:7b:7a:42:02:13 p2p_dev_addr=fa:7b:7a:42:02:13 pri_dev_type=1-0050F204-1 146 name='p2p-TEST1' config_methods=0x188 dev_capab=0x27 group_capab=0x0 */ 147 private static final String P2P_DEVICE_FOUND_STR = "P2P-DEVICE-FOUND"; 148 149 /* P2P-DEVICE-LOST p2p_dev_addr=42:fc:89:e1:e2:27 */ 150 private static final String P2P_DEVICE_LOST_STR = "P2P-DEVICE-LOST"; 151 152 /* P2P-GO-NEG-REQUEST 42:fc:89:a8:96:09 dev_passwd_id=4 */ 153 private static final String P2P_GO_NEG_REQUEST_STR = "P2P-GO-NEG-REQUEST"; 154 155 private static final String P2P_GO_NEG_SUCCESS_STR = "P2P-GO-NEG-SUCCESS"; 156 157 private static final String P2P_GO_NEG_FAILURE_STR = "P2P-GO-NEG-FAILURE"; 158 159 private static final String P2P_GROUP_FORMATION_SUCCESS_STR = 160 "P2P-GROUP-FORMATION-SUCCESS"; 161 162 private static final String P2P_GROUP_FORMATION_FAILURE_STR = 163 "P2P-GROUP-FORMATION-FAILURE"; 164 165 /* P2P-GROUP-STARTED p2p-wlan0-0 [client|GO] ssid="DIRECT-W8" freq=2437 166 [psk=2182b2e50e53f260d04f3c7b25ef33c965a3291b9b36b455a82d77fd82ca15bc|passphrase="fKG4jMe3"] 167 go_dev_addr=fa:7b:7a:42:02:13 */ 168 private static final String P2P_GROUP_STARTED_STR = "P2P-GROUP-STARTED"; 169 170 /* P2P-GROUP-REMOVED p2p-wlan0-0 [client|GO] reason=REQUESTED */ 171 private static final String P2P_GROUP_REMOVED_STR = "P2P-GROUP-REMOVED"; 172 173 /* P2P-INVITATION-RECEIVED sa=fa:7b:7a:42:02:13 go_dev_addr=f8:7b:7a:42:02:13 174 bssid=fa:7b:7a:42:82:13 unknown-network */ 175 private static final String P2P_INVITATION_RECEIVED_STR = "P2P-INVITATION-RECEIVED"; 176 177 /* P2P-INVITATION-RESULT status=1 */ 178 private static final String P2P_INVITATION_RESULT_STR = "P2P-INVITATION-RESULT"; 179 180 /* P2P-PROV-DISC-PBC-REQ 42:fc:89:e1:e2:27 p2p_dev_addr=42:fc:89:e1:e2:27 181 pri_dev_type=1-0050F204-1 name='p2p-TEST2' config_methods=0x188 dev_capab=0x27 182 group_capab=0x0 */ 183 private static final String P2P_PROV_DISC_PBC_REQ_STR = "P2P-PROV-DISC-PBC-REQ"; 184 /* P2P-PROV-DISC-ENTER-PIN 42:fc:89:e1:e2:27 p2p_dev_addr=42:fc:89:e1:e2:27 185 pri_dev_type=1-0050F204-1 name='p2p-TEST2' config_methods=0x188 dev_capab=0x27 186 group_capab=0x0 */ 187 private static final String P2P_PROV_DISC_ENTER_PIN_STR = "P2P-PROV-DISC-ENTER-PIN"; 188 /* P2P-PROV-DISC-SHOW-PIN 42:fc:89:e1:e2:27 44490607 p2p_dev_addr=42:fc:89:e1:e2:27 189 pri_dev_type=1-0050F204-1 name='p2p-TEST2' config_methods=0x188 dev_capab=0x27 190 group_capab=0x0 */ 191 private static final String P2P_PROV_DISC_SHOW_PIN_STR = "P2P-PROV-DISC-SHOW-PIN"; 192 193 private static final String HOST_AP_EVENT_PREFIX_STR = "AP"; 194 /* AP-STA-CONNECTED 42:fc:89:a8:96:09 */ 195 private static final String AP_STA_CONNECTED_STR = "AP-STA-CONNECTED"; 196 /* AP-STA-DISCONNECTED 42:fc:89:a8:96:09 */ 197 private static final String AP_STA_DISCONNECTED_STR = "AP-STA-DISCONNECTED"; 198 199 private final StateMachine mStateMachine; 200 201 /* Supplicant events reported to a state machine */ 202 private static final int BASE = Protocol.BASE_WIFI_MONITOR; 203 204 /* Connection to supplicant established */ 205 public static final int SUP_CONNECTION_EVENT = BASE + 1; 206 /* Connection to supplicant lost */ 207 public static final int SUP_DISCONNECTION_EVENT = BASE + 2; 208 /* Network connection completed */ 209 public static final int NETWORK_CONNECTION_EVENT = BASE + 3; 210 /* Network disconnection completed */ 211 public static final int NETWORK_DISCONNECTION_EVENT = BASE + 4; 212 /* Scan results are available */ 213 public static final int SCAN_RESULTS_EVENT = BASE + 5; 214 /* Supplicate state changed */ 215 public static final int SUPPLICANT_STATE_CHANGE_EVENT = BASE + 6; 216 /* Password failure and EAP authentication failure */ 217 public static final int AUTHENTICATION_FAILURE_EVENT = BASE + 7; 218 /* WPS overlap detected */ 219 public static final int WPS_OVERLAP_EVENT = BASE + 8; 220 /* Driver was hung */ 221 public static final int DRIVER_HUNG_EVENT = BASE + 9; 222 223 /* P2P events */ 224 public static final int P2P_DEVICE_FOUND_EVENT = BASE + 21; 225 public static final int P2P_DEVICE_LOST_EVENT = BASE + 22; 226 public static final int P2P_GO_NEGOTIATION_REQUEST_EVENT = BASE + 23; 227 public static final int P2P_GO_NEGOTIATION_SUCCESS_EVENT = BASE + 25; 228 public static final int P2P_GO_NEGOTIATION_FAILURE_EVENT = BASE + 26; 229 public static final int P2P_GROUP_FORMATION_SUCCESS_EVENT = BASE + 27; 230 public static final int P2P_GROUP_FORMATION_FAILURE_EVENT = BASE + 28; 231 public static final int P2P_GROUP_STARTED_EVENT = BASE + 29; 232 public static final int P2P_GROUP_REMOVED_EVENT = BASE + 30; 233 public static final int P2P_INVITATION_RECEIVED_EVENT = BASE + 31; 234 public static final int P2P_INVITATION_RESULT_EVENT = BASE + 32; 235 public static final int P2P_PROV_DISC_PBC_REQ_EVENT = BASE + 33; 236 public static final int P2P_PROV_DISC_ENTER_PIN_EVENT = BASE + 34; 237 public static final int P2P_PROV_DISC_SHOW_PIN_EVENT = BASE + 35; 238 239 /* hostap events */ 240 public static final int AP_STA_DISCONNECTED_EVENT = BASE + 41; 241 public static final int AP_STA_CONNECTED_EVENT = BASE + 42; 242 243 /** 244 * This indicates the supplicant connection for the monitor is closed 245 */ 246 private static final String MONITOR_SOCKET_CLOSED_STR = "connection closed"; 247 248 /** 249 * This indicates a read error on the monitor socket conenction 250 */ 251 private static final String WPA_RECV_ERROR_STR = "recv error"; 252 253 /** 254 * Tracks consecutive receive errors 255 */ 256 private int mRecvErrors = 0; 257 258 /** 259 * Max errors before we close supplicant connection 260 */ 261 private static final int MAX_RECV_ERRORS = 10; 262 263 public WifiMonitor(StateMachine wifiStateMachine) { 264 mStateMachine = wifiStateMachine; 265 } 266 267 public void startMonitoring() { 268 new MonitorThread().start(); 269 } 270 271 class MonitorThread extends Thread { 272 public MonitorThread() { 273 super("WifiMonitor"); 274 } 275 276 public void run() { 277 278 if (connectToSupplicant()) { 279 // Send a message indicating that it is now possible to send commands 280 // to the supplicant 281 mStateMachine.sendMessage(SUP_CONNECTION_EVENT); 282 } else { 283 mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT); 284 return; 285 } 286 287 //noinspection InfiniteLoopStatement 288 for (;;) { 289 String eventStr = WifiNative.waitForEvent(); 290 291 // Skip logging the common but mostly uninteresting scan-results event 292 if (false && eventStr.indexOf(SCAN_RESULTS_STR) == -1) { 293 Log.d(TAG, "Event [" + eventStr + "]"); 294 } 295 if (!eventStr.startsWith(EVENT_PREFIX_STR)) { 296 if (eventStr.startsWith(WPA_EVENT_PREFIX_STR) && 297 0 < eventStr.indexOf(PASSWORD_MAY_BE_INCORRECT_STR)) { 298 mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT); 299 } else if (eventStr.startsWith(WPS_OVERLAP_STR)) { 300 mStateMachine.sendMessage(WPS_OVERLAP_EVENT); 301 } else if (eventStr.startsWith(P2P_EVENT_PREFIX_STR)) { 302 handleP2pEvents(eventStr); 303 } else if (eventStr.startsWith(HOST_AP_EVENT_PREFIX_STR)) { 304 handleHostApEvents(eventStr); 305 } 306 continue; 307 } 308 309 String eventName = eventStr.substring(EVENT_PREFIX_LEN_STR); 310 int nameEnd = eventName.indexOf(' '); 311 if (nameEnd != -1) 312 eventName = eventName.substring(0, nameEnd); 313 if (eventName.length() == 0) { 314 if (false) Log.i(TAG, "Received wpa_supplicant event with empty event name"); 315 continue; 316 } 317 /* 318 * Map event name into event enum 319 */ 320 int event; 321 if (eventName.equals(CONNECTED_STR)) 322 event = CONNECTED; 323 else if (eventName.equals(DISCONNECTED_STR)) 324 event = DISCONNECTED; 325 else if (eventName.equals(STATE_CHANGE_STR)) 326 event = STATE_CHANGE; 327 else if (eventName.equals(SCAN_RESULTS_STR)) 328 event = SCAN_RESULTS; 329 else if (eventName.equals(LINK_SPEED_STR)) 330 event = LINK_SPEED; 331 else if (eventName.equals(TERMINATING_STR)) 332 event = TERMINATING; 333 else if (eventName.equals(DRIVER_STATE_STR)) 334 event = DRIVER_STATE; 335 else if (eventName.equals(EAP_FAILURE_STR)) 336 event = EAP_FAILURE; 337 else 338 event = UNKNOWN; 339 340 String eventData = eventStr; 341 if (event == DRIVER_STATE || event == LINK_SPEED) 342 eventData = eventData.split(" ")[1]; 343 else if (event == STATE_CHANGE || event == EAP_FAILURE) { 344 int ind = eventStr.indexOf(" "); 345 if (ind != -1) { 346 eventData = eventStr.substring(ind + 1); 347 } 348 } else { 349 int ind = eventStr.indexOf(" - "); 350 if (ind != -1) { 351 eventData = eventStr.substring(ind + 3); 352 } 353 } 354 355 if (event == STATE_CHANGE) { 356 handleSupplicantStateChange(eventData); 357 } else if (event == DRIVER_STATE) { 358 handleDriverEvent(eventData); 359 } else if (event == TERMINATING) { 360 /** 361 * If monitor socket is closed, we have already 362 * stopped the supplicant, simply exit the monitor thread 363 */ 364 if (eventData.startsWith(MONITOR_SOCKET_CLOSED_STR)) { 365 if (false) { 366 Log.d(TAG, "Monitor socket is closed, exiting thread"); 367 } 368 break; 369 } 370 371 /** 372 * Close the supplicant connection if we see 373 * too many recv errors 374 */ 375 if (eventData.startsWith(WPA_RECV_ERROR_STR)) { 376 if (++mRecvErrors > MAX_RECV_ERRORS) { 377 if (false) { 378 Log.d(TAG, "too many recv errors, closing connection"); 379 } 380 } else { 381 continue; 382 } 383 } 384 385 // notify and exit 386 mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT); 387 break; 388 } else if (event == EAP_FAILURE) { 389 if (eventData.startsWith(EAP_AUTH_FAILURE_STR)) { 390 mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT); 391 } 392 } else { 393 handleEvent(event, eventData); 394 } 395 mRecvErrors = 0; 396 } 397 } 398 399 private boolean connectToSupplicant() { 400 int connectTries = 0; 401 402 while (true) { 403 if (WifiNative.connectToSupplicant()) { 404 return true; 405 } 406 if (connectTries++ < 5) { 407 nap(1); 408 } else { 409 break; 410 } 411 } 412 return false; 413 } 414 415 private void handleDriverEvent(String state) { 416 if (state == null) { 417 return; 418 } 419 if (state.equals("HANGED")) { 420 mStateMachine.sendMessage(DRIVER_HUNG_EVENT); 421 } 422 } 423 424 /** 425 * Handle all supplicant events except STATE-CHANGE 426 * @param event the event type 427 * @param remainder the rest of the string following the 428 * event name and " — " 429 */ 430 void handleEvent(int event, String remainder) { 431 switch (event) { 432 case DISCONNECTED: 433 handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED, remainder); 434 break; 435 436 case CONNECTED: 437 handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder); 438 break; 439 440 case SCAN_RESULTS: 441 mStateMachine.sendMessage(SCAN_RESULTS_EVENT); 442 break; 443 444 case UNKNOWN: 445 break; 446 } 447 } 448 449 /** 450 * Handle p2p events 451 */ 452 private void handleP2pEvents(String dataString) { 453 if (dataString.startsWith(P2P_DEVICE_FOUND_STR)) { 454 mStateMachine.sendMessage(P2P_DEVICE_FOUND_EVENT, new WifiP2pDevice(dataString)); 455 } else if (dataString.startsWith(P2P_DEVICE_LOST_STR)) { 456 mStateMachine.sendMessage(P2P_DEVICE_LOST_EVENT, new WifiP2pDevice(dataString)); 457 } else if (dataString.startsWith(P2P_GO_NEG_REQUEST_STR)) { 458 mStateMachine.sendMessage(P2P_GO_NEGOTIATION_REQUEST_EVENT, 459 new WifiP2pConfig(dataString)); 460 } else if (dataString.startsWith(P2P_GO_NEG_SUCCESS_STR)) { 461 mStateMachine.sendMessage(P2P_GO_NEGOTIATION_SUCCESS_EVENT); 462 } else if (dataString.startsWith(P2P_GO_NEG_FAILURE_STR)) { 463 mStateMachine.sendMessage(P2P_GO_NEGOTIATION_FAILURE_EVENT); 464 } else if (dataString.startsWith(P2P_GROUP_FORMATION_SUCCESS_STR)) { 465 mStateMachine.sendMessage(P2P_GROUP_FORMATION_SUCCESS_EVENT); 466 } else if (dataString.startsWith(P2P_GROUP_FORMATION_FAILURE_STR)) { 467 mStateMachine.sendMessage(P2P_GROUP_FORMATION_FAILURE_EVENT); 468 } else if (dataString.startsWith(P2P_GROUP_STARTED_STR)) { 469 mStateMachine.sendMessage(P2P_GROUP_STARTED_EVENT, new WifiP2pGroup(dataString)); 470 } else if (dataString.startsWith(P2P_GROUP_REMOVED_STR)) { 471 mStateMachine.sendMessage(P2P_GROUP_REMOVED_EVENT, new WifiP2pGroup(dataString)); 472 } else if (dataString.startsWith(P2P_INVITATION_RECEIVED_STR)) { 473 mStateMachine.sendMessage(P2P_INVITATION_RECEIVED_EVENT, 474 new WifiP2pGroup(dataString)); 475 } else if (dataString.startsWith(P2P_INVITATION_RESULT_STR)) { 476 String[] tokens = dataString.split(" "); 477 if (tokens.length != 2) return; 478 String[] nameValue = tokens[1].split("="); 479 if (nameValue.length != 2) return; 480 mStateMachine.sendMessage(P2P_INVITATION_RESULT_EVENT, nameValue[1]); 481 } else if (dataString.startsWith(P2P_PROV_DISC_PBC_REQ_STR)) { 482 mStateMachine.sendMessage(P2P_PROV_DISC_PBC_REQ_EVENT, 483 new WifiP2pDevice(dataString)); 484 } else if (dataString.startsWith(P2P_PROV_DISC_ENTER_PIN_STR)) { 485 mStateMachine.sendMessage(P2P_PROV_DISC_ENTER_PIN_EVENT, 486 new WifiP2pDevice(dataString)); 487 } 488 } 489 490 /** 491 * Handle hostap events 492 */ 493 private void handleHostApEvents(String dataString) { 494 String[] tokens = dataString.split(" "); 495 if (tokens[0].equals(AP_STA_CONNECTED_STR)) { 496 mStateMachine.sendMessage(AP_STA_CONNECTED_EVENT, tokens[1]); 497 } else if (tokens[0].equals(AP_STA_DISCONNECTED_STR)) { 498 mStateMachine.sendMessage(AP_STA_DISCONNECTED_EVENT, tokens[1]); 499 } 500 } 501 502 /** 503 * Handle the supplicant STATE-CHANGE event 504 * @param dataString New supplicant state string in the format: 505 * id=network-id state=new-state 506 */ 507 private void handleSupplicantStateChange(String dataString) { 508 String[] dataTokens = dataString.split(" "); 509 510 String BSSID = null; 511 int networkId = -1; 512 int newState = -1; 513 for (String token : dataTokens) { 514 String[] nameValue = token.split("="); 515 if (nameValue.length != 2) { 516 continue; 517 } 518 519 if (nameValue[0].equals("BSSID")) { 520 BSSID = nameValue[1]; 521 continue; 522 } 523 524 int value; 525 try { 526 value = Integer.parseInt(nameValue[1]); 527 } catch (NumberFormatException e) { 528 Log.w(TAG, "STATE-CHANGE non-integer parameter: " + token); 529 continue; 530 } 531 532 if (nameValue[0].equals("id")) { 533 networkId = value; 534 } else if (nameValue[0].equals("state")) { 535 newState = value; 536 } 537 } 538 539 if (newState == -1) return; 540 541 SupplicantState newSupplicantState = SupplicantState.INVALID; 542 for (SupplicantState state : SupplicantState.values()) { 543 if (state.ordinal() == newState) { 544 newSupplicantState = state; 545 break; 546 } 547 } 548 if (newSupplicantState == SupplicantState.INVALID) { 549 Log.w(TAG, "Invalid supplicant state: " + newState); 550 } 551 notifySupplicantStateChange(networkId, BSSID, newSupplicantState); 552 } 553 } 554 555 private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data) { 556 String BSSID = null; 557 int networkId = -1; 558 if (newState == NetworkInfo.DetailedState.CONNECTED) { 559 Matcher match = mConnectedEventPattern.matcher(data); 560 if (!match.find()) { 561 if (false) Log.d(TAG, "Could not find BSSID in CONNECTED event string"); 562 } else { 563 BSSID = match.group(1); 564 try { 565 networkId = Integer.parseInt(match.group(2)); 566 } catch (NumberFormatException e) { 567 networkId = -1; 568 } 569 } 570 } 571 notifyNetworkStateChange(newState, BSSID, networkId); 572 } 573 574 /** 575 * Send the state machine a notification that the state of Wifi connectivity 576 * has changed. 577 * @param networkId the configured network on which the state change occurred 578 * @param newState the new network state 579 * @param BSSID when the new state is {@link DetailedState#CONNECTED 580 * NetworkInfo.DetailedState.CONNECTED}, 581 * this is the MAC address of the access point. Otherwise, it 582 * is {@code null}. 583 */ 584 void notifyNetworkStateChange(NetworkInfo.DetailedState newState, String BSSID, int netId) { 585 if (newState == NetworkInfo.DetailedState.CONNECTED) { 586 Message m = mStateMachine.obtainMessage(NETWORK_CONNECTION_EVENT, 587 netId, 0, BSSID); 588 mStateMachine.sendMessage(m); 589 } else { 590 Message m = mStateMachine.obtainMessage(NETWORK_DISCONNECTION_EVENT, 591 netId, 0, BSSID); 592 mStateMachine.sendMessage(m); 593 } 594 } 595 596 /** 597 * Send the state machine a notification that the state of the supplicant 598 * has changed. 599 * @param networkId the configured network on which the state change occurred 600 * @param newState the new {@code SupplicantState} 601 */ 602 void notifySupplicantStateChange(int networkId, String BSSID, SupplicantState newState) { 603 mStateMachine.sendMessage(mStateMachine.obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT, 604 new StateChangeResult(networkId, BSSID, newState))); 605 } 606 607 /** 608 * Sleep for a period of time. 609 * @param secs the number of seconds to sleep 610 */ 611 private static void nap(int secs) { 612 try { 613 Thread.sleep(secs * 1000); 614 } catch (InterruptedException ignore) { 615 } 616 } 617 } 618