本章主要介绍用户手动的在Settings中点击Scan和Connect按钮,输入密码后的连接过程,先看整体流程图:
public boolean startScan(WorkSource workSource) { try { mService.startScan(workSource); return true; } catch (RemoteException e) { return false; } }
WifiService.java public void startScan(WorkSource workSource) { enforceChangePermission(); if (workSource != null) { enforceWorkSourcePermission(); // WifiManager currently doesn't use names, so need to clear names out of the // supplied WorkSource to allow future WorkSource combining. workSource.clearNames(); } mWifiStateMachine.startScan(Binder.getCallingUid(), workSource); }
public boolean processMessage(Message message) { switch(message.what) { case CMD_START_SCAN: noteScanStart(message.arg1, (WorkSource) message.obj); startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP); break;
case WifiMonitor.SCAN_RESULTS_EVENT: setScanResults(); sendScanResultsAvailableBroadcast(); mScanResultIsPending = false; break;
private void setScanResults() { while (true) { tmpResults = mWifiNative.scanResults(sid); if (TextUtils.isEmpty(tmpResults)) break; scanResultsBuf.append(tmpResults); scanResultsBuf.append("\n"); String[] lines = tmpResults.split("\n"); sid = -1; for (int i=lines.length - 1; i >= 0; i--) { if (lines[i].startsWith(END_STR)) { break; } else if (lines[i].startsWith(ID_STR)) { try { sid = Integer.parseInt(lines[i].substring(ID_STR.length())) + 1; } catch (NumberFormatException e) { // Nothing to do } break; } } if (sid == -1) break; } scanResults = scanResultsBuf.toString(); if (TextUtils.isEmpty(scanResults)) { return; } synchronized(mScanResultCache) { for (String line : lines) { if (line.startsWith(BSSID_STR)) { bssid = new String(line.getBytes(), bssidStrLen, line.length() - bssidStrLen); } else if (line.startsWith(FREQ_STR)) { try { freq = Integer.parseInt(line.substring(FREQ_STR.length())); } catch (NumberFormatException e) { freq = 0; } } else if (line.startsWith(SSID_STR)) { wifiSsid = WifiSsid.createFromAsciiEncoded( line.substring(SSID_STR.length())); } else if (line.startsWith(DELIMITER_STR) || line.startsWith(END_STR)) { if (bssid != null) { String ssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; String key = bssid + ssid; ScanResult scanResult = mScanResultCache.get(key); if (scanResult != null) { scanResult.level = level; scanResult.wifiSsid = wifiSsid; // Keep existing API scanResult.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; scanResult.capabilities = flags; scanResult.frequency = freq; scanResult.timestamp = tsf; } else { scanResult = new ScanResult( wifiSsid, bssid, flags, level, freq, tsf); mScanResultCache.put(key, scanResult); } mScanResults.add(scanResult); }
public void connect(WifiConfiguration config, ActionListener listener) { if (config == null) throw new IllegalArgumentException("config cannot be null"); validateChannel(); // Use INVALID_NETWORK_ID for arg1 when passing a config object // arg1 is used to pass network id when the network already exists sAsyncChannel.sendMessage(CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID, putListener(listener), config); }
case WifiManager.CONNECT_NETWORK: case WifiManager.SAVE_NETWORK: { WifiConfiguration config = (WifiConfiguration) msg.obj; int networkId = msg.arg1; if (config != null && config.isValid()) { // This is restricted because there is no UI for the user to // monitor/control PAC. if (config.proxySettings != ProxySettings.PAC) { if (DBG) Slog.d(TAG, "Connect with config" + config); mWifiStateMachine.sendMessage(Message.obtain(msg)); } reak; }
case WifiManager.CONNECT_NETWORK: int netId = message.arg1; config = (WifiConfiguration) message.obj; /* Save the network config */ if (config != null) { NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); netId = result.getNetworkId(); } if (mWifiConfigStore.selectNetwork(netId) && mWifiNative.reconnect()) { /* The state tracker handles enabling networks upon completion/failure */ mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK); replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); /* Expect a disconnection from the old connection */ transitionTo(mDisconnectingState); } break;
class DisconnectingState extends State { @Override public boolean processMessage(Message message) { switch (message.what) { case CMD_SET_OPERATIONAL_MODE: if (message.arg1 != CONNECT_MODE) { deferMessage(message); } break; case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: /* If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT * we have missed the network disconnection, transition to mDisconnectedState * and handle the rest of the events there */ deferMessage(message); handleNetworkDisconnect(); transitionTo(mDisconnectedState); break; default: return NOT_HANDLED; } return HANDLED; } }
case WifiMonitor.NETWORK_CONNECTION_EVENT: if (DBG) log("Network connection established"); mLastNetworkId = message.arg1; mLastBssid = (String) message.obj; mWifiInfo.setBSSID(mLastBssid); mWifiInfo.setNetworkId(mLastNetworkId); /* send event to CM & network change broadcast */ setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); sendNetworkStateChangeBroadcast(mLastBssid); transitionTo(mObtainingIpState); break;
class ObtainingIpState extends State { @Override public void enter() { if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { // TODO: If we're switching between static IP configuration and DHCP, remove the // static configuration first. startDhcp(); } else { // stop any running dhcp before assigning static IP stopDhcp(); DhcpResults dhcpResults = new DhcpResults( mWifiConfigStore.getLinkProperties(mLastNetworkId)); InterfaceConfiguration ifcg = new InterfaceConfiguration(); Iterator<LinkAddress> addrs = dhcpResults.linkProperties.getLinkAddresses().iterator(); if (!addrs.hasNext()) { loge("Static IP lacks address"); sendMessage(CMD_STATIC_IP_FAILURE); } else { ifcg.setLinkAddress(addrs.next()); ifcg.setInterfaceUp(); try { mNwService.setInterfaceConfig(mInterfaceName, ifcg); if (DBG) log("Static IP configuration succeeded"); sendMessage(CMD_STATIC_IP_SUCCESS, dhcpResults); } catch (RemoteException re) { loge("Static IP configuration failed: " + re); sendMessage(CMD_STATIC_IP_FAILURE); } catch (IllegalStateException e) { loge("Static IP configuration failed: " + e); sendMessage(CMD_STATIC_IP_FAILURE); } } } }
void startDhcp() { if (mDhcpStateMachine == null) { mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine( mContext, WifiStateMachine.this, mInterfaceName); } mDhcpStateMachine.registerForPreDhcpNotification(); mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); }
public boolean processMessage(Message message) { switch (message.what) { case DhcpStateMachine.CMD_PRE_DHCP_ACTION: handlePreDhcpSetup(); break; case DhcpStateMachine.CMD_POST_DHCP_ACTION: handlePostDhcpSetup(); if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) { if (DBG) log("DHCP successful"); handleSuccessfulIpConfiguration((DhcpResults) message.obj); transitionTo(mVerifyingLinkState); } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) { if (DBG) log("DHCP failed"); handleFailedIpConfiguration(); transitionTo(mDisconnectingState); } break;
class VerifyingLinkState extends State { @Override public void enter() { log(getName() + " enter"); setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK); mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK); sendNetworkStateChangeBroadcast(mLastBssid); } @Override public boolean processMessage(Message message) { switch (message.what) { case WifiWatchdogStateMachine.POOR_LINK_DETECTED: //stay here log(getName() + " POOR_LINK_DETECTED: no transition"); break; case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: log(getName() + " GOOD_LINK_DETECTED: transition to captive portal check"); transitionTo(mCaptivePortalCheckState); break; default: if (DBG) log(getName() + " what=" + message.what + " NOT_HANDLED"); return NOT_HANDLED; } return HANDLED; } }
class CaptivePortalCheckState extends State { @Override public void enter() { log(getName() + " enter"); setNetworkDetailedState(DetailedState.CAPTIVE_PORTAL_CHECK); mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CAPTIVE_PORTAL_CHECK); sendNetworkStateChangeBroadcast(mLastBssid); } @Override public boolean processMessage(Message message) { switch (message.what) { case CMD_CAPTIVE_CHECK_COMPLETE: log(getName() + " CMD_CAPTIVE_CHECK_COMPLETE"); try { mNwService.enableIpv6(mInterfaceName); } catch (RemoteException re) { loge("Failed to enable IPv6: " + re); } catch (IllegalStateException e) { loge("Failed to enable IPv6: " + e); } setNetworkDetailedState(DetailedState.CONNECTED); mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED); sendNetworkStateChangeBroadcast(mLastBssid); transitionTo(mConnectedState); break; default: return NOT_HANDLED; } return HANDLED; } }