本章主要介绍用户手动的在Settings中点击Scan和Connect按钮,输入密码后的连接过程,先看整体流程图:
WiFi Scan过程分析
当用户进入Settings点击Scan后,就会调用到WifiManager的startScan()方法,当然在Settings里面有设置Scan的定时器,每隔一段时间就会去scan,在Wifi Framework中也有scan的定时器。对照上面的流程图,来看一下WifiManager的startScan()方法:
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);
}
WiFiStateMachine的startScan方法会给自己发送一个CMD_START_SCAN的message,由前面toggle on wifi的知识,这个消息将由DisconnectedState及其父State来处理,从代码中可以很容易的分析到,CMD_START_SCAN将会被DriverStartedState 来处理,进入到处理的代码中:
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;
noteScanStart是用于通知电量统计用;startScanNative会向wpa_supplicant发送SCAN的命令,当wpa_suppliant执行完SCAN并成功找到一些AP后,就会给WifiMonitor发送CTRL-EVENT-SCAN-RESULTS的event,WifiMonitor会parse出这个event,并向WifiStateMachine发送SCAN_RESULTS_EVENT消息,WifiStateMachine的SupplicantStartedState会处理这个消息,如下:
case WifiMonitor.SCAN_RESULTS_EVENT:
setScanResults();
sendScanResultsAvailableBroadcast();
mScanResultIsPending = false;
break;
这里主要做了两件事,一是去获取scanResults,另外会发送一个广播信息出去,如果有检测这个广播的receive收到这个广播后,就可以调用函数去获取到scanResults并显示到listview上面,例如WifiSettings。进入到setScanResults里面来分析:
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)