一、wifi模块的结构
当设置enable后,调用WifiEnabler->WifiManager->WifiService->
WifiNatvie->android_net_wifi_wifi->wifi.c->wpa_supplicant.
同时还有wifi事件的监听,密码设置
WifiSettings->AccessPoint->WifiService->WifiStateTracker->WifiMonitor->WifiNatvie->android_net_wifi_wifi->wifi.c->wpa_supplicant.
其中wpa_supplicant是通过socket与 hardware/libhardware_legacy/wifi/wifi.c通信
二、wifi服务的启动
在SystemServer启动时,生成一个 ConnectivityService 的实例
try {
Slog.i(TAG, "Connectivity Service");
connectivity = ConnectivityService.getInstance(context);
ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
} catch (Throwable e) {
Slog.e(TAG, "Failure starting Connectivity Service", e);
}
在 ConnectivityService的构造函数里创建WifiService.
case ConnectivityManager.TYPE_WIFI:
if (DBG) Slog.v(TAG, "Starting Wifi Service.");
WifiStateTracker wst = new WifiStateTracker(context, mHandler);
WifiService wifiService = new WifiService(context, wst);
ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
wifiService.startWifi();//调用wifiService的startWifi
mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
wst.startMonitoring();//启动监听
WifiService 负责启动关闭 wpa_supplicant、启动关闭 WifiMonitor 监视线程和把命令下发给wpa_supplicant,而 WifiMonitor 则负责从wpa_supplicant 接收事件通知。
三、enable AP
WirelessSettings 在初始化的时候配置了WifiEnabler
protected void onCreate(Bundle savedInstanceState) {
....
mWifiEnabler = new WifiEnabler(this, wifi);
...
}
点击按钮创建WifiEnabler,由WifiEnabler调用 WifiManager 的 setWifiEnabled 接口函数,最终它调用WifiService的setWifiEnabled函数。然后sendEnableMessage到Wifiservice。
WifiService.java:
private class WifiHandler extends Handler {
public WifiHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_ENABLE_WIFI:
setWifiEnabledBlocking(true, msg.arg1 == 1, msg.arg2);
if (mWifiWatchdogService == null) {
mWifiWatchdogService = new WifiWatchdogService(mContext, mWifiStateTracker);
}
sWakeLock.release();
break;
....
}
WifiService收到MESSAGE_ENABLE_WIFI消息,调用setWifiEnabledBlocking函数。
private boolean setWifiEnabledBlocking(boolean enable, boolean persist, int uid) {
final int eventualWifiState = enable ? WIFI_STATE_ENABLED : WIFI_STATE_DISABLED;
final int wifiState = mWifiStateTracker.getWifiState();
if (wifiState == eventualWifiState) {
return true;
}
if (enable && isAirplaneModeOn() && !mAirplaneModeOverwridden) {
return false;
}
/**
* Multiple calls to unregisterReceiver() cause exception and a system crash.
* This can happen if a supplicant is lost (or firmware crash occurs) and user indicates
* disable wifi at the same time.
* Avoid doing a disable when the current Wifi state is UNKNOWN
* TODO: Handle driver load fail and supplicant lost as seperate states
*/
if ((wifiState == WIFI_STATE_UNKNOWN) && !enable) {
return false;
}
/**
* Fail Wifi if AP is enabled
* TODO: Deprecate WIFI_STATE_UNKNOWN and rename it
* WIFI_STATE_FAILED
*/
if ((mWifiApState == WIFI_AP_STATE_ENABLED) && enable) {
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
return false;
}
setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING, uid);
if (enable) {
if (!mWifiStateTracker.loadDriver()) {
Slog.e(TAG, "Failed to load Wi-Fi driver.");
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
return false;
}
if (!mWifiStateTracker.startSupplicant()) {
mWifiStateTracker.unloadDriver();
Slog.e(TAG, "Failed to start supplicant daemon.");
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
return false;
}
registerForBroadcasts();
mWifiStateTracker.startEventLoop();
} else {
mContext.unregisterReceiver(mReceiver);
// Remove notification (it will no-op if it isn't visible)
mWifiStateTracker.setNotificationVisible(false, 0, false, 0);
boolean failedToStopSupplicantOrUnloadDriver = false;
if (!mWifiStateTracker.stopSupplicant()) {
Slog.e(TAG, "Failed to stop supplicant daemon.");
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
failedToStopSupplicantOrUnloadDriver = true;
}
/**
* Reset connections and disable interface
* before we unload the driver
*/
mWifiStateTracker.resetConnections(true);
if (!mWifiStateTracker.unloadDriver()) {
Slog.e(TAG, "Failed to unload Wi-Fi driver.");
if (!failedToStopSupplicantOrUnloadDriver) {
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
failedToStopSupplicantOrUnloadDriver = true;
}
}
if (failedToStopSupplicantOrUnloadDriver) {
return false;
}
}
// Success!
if (persist) {
persistWifiEnabled(enable);
}
setWifiEnabledState(eventualWifiState, uid);
return true;
}
这个函数主要做三件事,一是加载wifi驱动模块,二是启动wpa_supplicant。之后是通过WifiStateTracker 来启动 WifiMonitor的事件监听线程。
设置成功后,更新wifi状态,以广播方式发送WIFI_STATE_CHANGED_ACTION这个Intent。通知外界WIFI已经enable成功。代码如下:
private void setWifiEnabledState(int wifiState, int uid) {
final int previousWifiState = mWifiStateTracker.getWifiState();
long ident = Binder.clearCallingIdentity();
try {
if (wifiState == WIFI_STATE_ENABLED) {
mBatteryStats.noteWifiOn();
} else if (wifiState == WIFI_STATE_DISABLED) {
mBatteryStats.noteWifiOff();
}
} catch (RemoteException e) {
} finally {
Binder.restoreCallingIdentity(ident);
}
// Update state
mWifiStateTracker.setWifiState(wifiState);
// Broadcast
final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
mContext.sendStickyBroadcast(intent);
}
外界接受到WIFI_STATE_CHANGED_ACTION这个Intent后,在WifiSettings.java里
private void updateWifiState(int state) {
if (state == WifiManager.WIFI_STATE_ENABLED) {
mScanner.resume();
updateAccessPoints();
} else {
mScanner.pause();
mAccessPoints.removeAll();
}
}
开始扫描,并update AccessPoints.
追踪代码,扫描函数在WifiStateTracker.java里
public synchronized boolean scan(boolean forceActive) {
if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) {
return false;
}
return WifiNative.scanCommand(forceActive);
}
在android_net_wifi_Wifi.cpp,也是往 wpa_supplicant 发送 SCAN 命令
static jboolean android_net_wifi_scanCommand(JNIEnv* env, jobject clazz, jboolean forceActive)
{
jboolean result;
// Ignore any error from setting the scan mode.
// The scan will still work.
if (forceActive && !sScanModeActive)
doSetScanMode(true);
result = doBooleanCommand("SCAN", "OK");
if (forceActive && !sScanModeActive)
doSetScanMode(sScanModeActive);
return result;
}
获取扫描结果,并向控制台发送扫描事件。由于WifiMonitor.java的startMonitoring函数已经启动,监听线程已经启动。
在WifiMonitor.java里
class MonitorThread extends Thread {
public MonitorThread() {
super("WifiMonitor");
}
public void run() {
if (connectToSupplicant()) {
// Send a message indicating that it is now possible to send commands
// to the supplicant
mWifiStateTracker.notifySupplicantConnection();
} else {
mWifiStateTracker.notifySupplicantLost();
return;
}
//noinspection InfiniteLoopStatement
for (;;) {
String eventStr = WifiNative.waitForEvent();
// Skip logging the common but mostly uninteresting scan-results event
if (Config.LOGD && eventStr.indexOf(scanResultsEvent) == -1) {
Log.v(TAG, "Event [" + eventStr + "]");
}
if (!eventStr.startsWith(eventPrefix)) {
if (eventStr.startsWith(wpaEventPrefix) &&
0 < eventStr.indexOf(passwordKeyMayBeIncorrectEvent)) {
handlePasswordKeyMayBeIncorrect();
}
continue;
}
....
}
通过 WifiNative.waitForEvent()函数来接受扫描事件。
void handleEvent(int event, String remainder) {
switch (event) {
case DISCONNECTED:
handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED, remainder);
break;
case CONNECTED:
handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder);
break;
case SCAN_RESULTS:
mWifiStateTracker.notifyScanResultsAvailable();
break;
case UNKNOWN:
break;
}
}
void notifyScanResultsAvailable() {
// reset the supplicant's handling of scan results to "normal" mode
setScanResultHandling(SUPPL_SCAN_HANDLING_NORMAL);
sendEmptyMessage(EVENT_SCAN_RESULTS_AVAILABLE);
}
这样SCAN_RESULTS事件被执行。接着WifiStateTracker 则接着广播发送 SCAN_RESULTS_AVAILABLE_ACTION 这个 Intent
case EVENT_SCAN_RESULTS_AVAILABLE:
if (ActivityManagerNative.isSystemReady()) {
mContext.sendBroadcast(new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
}
sendScanResultsAvailable();
/**
* On receiving the first scan results after connecting to
* the supplicant, switch scan mode over to passive.
*/
setScanMode(false);
break;
在扫描完后,执行updateAccessPoints()函数:
WifiSettings.java:
private void updateAccessPoints() {
...
List<ScanResult> results = mWifiManager.getScanResults();//通过此函数获取AP扫描结果并保存在列表中。
if (results != null) {
for (ScanResult result : results) {
// Ignore hidden and ad-hoc networks.
if (result.SSID == null || result.SSID.length() == 0 ||
result.capabilities.contains("[IBSS]")) {
continue;
}
boolean found = false;
for (AccessPoint accessPoint : accessPoints) {
if (accessPoint.update(result)) {
found = true;
}
}
if (!found) {
accessPoints.add(new AccessPoint(this, result));
}
}
}
...
}
四、加密部分
在WifiDialog.java里:
ifiConfiguration getConfig() {
if (mAccessPoint != null && mAccessPoint.networkId != -1 && !edit) {
return null;
}
WifiConfiguration config = new WifiConfiguration();
if (mAccessPoint == null) {
config.SSID = AccessPoint.convertToQuotedString(
mSsid.getText().toString());
// If the user adds a network manually, assume that it is hidden.
config.hiddenSSID = true;
} else if (mAccessPoint.networkId == -1) {
config.SSID = AccessPoint.convertToQuotedString(
mAccessPoint.ssid);
} else {
config.networkId = mAccessPoint.networkId;
}
switch (mSecurity) {
case AccessPoint.SECURITY_NONE:
config.allowedKeyManagement.set(KeyMgmt.NONE);
return config;
//加密方式WEP
case AccessPoint.SECURITY_WEP:
config.allowedKeyManagement.set(KeyMgmt.NONE);
config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
if (mPassword.length() != 0) {
int length = mPassword.length();
String password = mPassword.getText().toString();
// WEP-40, WEP-104, and 256-bit WEP (WEP-232?)
if ((length == 10 || length == 26 || length == 58) &&
password.matches("[0-9A-Fa-f]*")) { //密码配对操作
config.wepKeys[0] = password;
} else {
config.wepKeys[0] = '"' + password + '"';
}
}
return config;
//PSK
case AccessPoint.SECURITY_PSK:
config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
if (mPassword.length() != 0) {
String password = mPassword.getText().toString();
if (password.matches("[0-9A-Fa-f]{64}")) { //密码配对操作
config.preSharedKey = password;
} else {
config.preSharedKey = '"' + password + '"';
}
}
return config;
//EAP
case AccessPoint.SECURITY_EAP:
config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
config.eap.setValue((String) mEapMethod.getSelectedItem());
config.phase2.setValue((mPhase2.getSelectedItemPosition() == 0) ? "" :
"auth=" + mPhase2.getSelectedItem());
config.ca_cert.setValue((mEapCaCert.getSelectedItemPosition() == 0) ? "" :
KEYSTORE_SPACE + Credentials.CA_CERTIFICATE +
(String) mEapCaCert.getSelectedItem());
config.client_cert.setValue((mEapUserCert.getSelectedItemPosition() == 0) ? "" :
KEYSTORE_SPACE + Credentials.USER_CERTIFICATE +
(String) mEapUserCert.getSelectedItem());
config.private_key.setValue((mEapUserCert.getSelectedItemPosition() == 0) ? "" :
KEYSTORE_SPACE + Credentials.USER_PRIVATE_KEY +
(String) mEapUserCert.getSelectedItem());
config.identity.setValue((mEapIdentity.length() == 0) ? "" :
mEapIdentity.getText().toString());
config.anonymous_identity.setValue((mEapAnonymous.length() == 0) ? "" :
mEapAnonymous.getText().toString());
if (mPassword.length() != 0) {
config.password.setValue(mPassword.getText().toString());
}
return config;
}
return null;
}
五、IP配置
当 wpa_supplicant 成功连接上 AP 之后,它会向控制通道发送事件通知连接上 AP 了,从而wifi_wait_for_event 函数会接收到该事件,由此 WifiMonitor 中的 MonitorThread 会被执行这个事件
void handleEvent(int event, String remainder) {
...
case CONNECTED:
handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED,remainder);
break;
...
}
追查handleNetworkStateChange函数
private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data) {
String BSSID = null;
int networkId = -1;
if (newState == NetworkInfo.DetailedState.CONNECTED) {
Matcher match = mConnectedEventPattern.matcher(data);
if (!match.find()) {
if (Config.LOGD) Log.d(TAG, "Could not find BSSID in CONNECTED event string");
} else {
BSSID = match.group(1);
try {
networkId = Integer.parseInt(match.group(2));
} catch (NumberFormatException e) {
networkId = -1;
}
}
}
mWifiStateTracker.notifyStateChange(newState, BSSID, networkId);
}
跟踪notifyStateChange
void notifyStateChange(DetailedState newState, String BSSID, int networkId) {
Message msg = Message.obtain(
this, EVENT_NETWORK_STATE_CHANGED,
new NetworkStateChangeResult(newState, BSSID, networkId));
msg.sendToTarget();
}
得到 EVENT_NETWORK_STATE_CHANGED事件
case EVENT_NETWORK_STATE_CHANGED:
....
if (result.state == DetailedState.CONNECTED) {//连接上
configureInterface();//配置IP
...
if (mHaveIpAddress) {//已经有IP地址没?
setDetailedState(DetailedState.CONNECTED);//有,已连接上
} else {
setDetailedState(DetailedState.OBTAINING_IPADDR);//木有,扫描获取IP地址
}
...
看看configureInterface()函数,WifiStateTracker 则接着会往自身发送 EVENT_DHCP_START 消息来启动 DHCP 去获取 IP 地址
private void configureInterface() {
checkPollTimer();
mLastSignalLevel = -1;
if (!mUseStaticIp) {
if (!mHaveIpAddress && !mObtainingIpAddress) {
mObtainingIpAddress = true;
mDhcpTarget.sendEmptyMessage(EVENT_DHCP_START);
}
} else {
int event;
if (NetworkUtils.configureInterface(mInterfaceName, mDhcpInfo)) {
mHaveIpAddress = true;
event = EVENT_INTERFACE_CONFIGURATION_SUCCEEDED;//获取IP地址成功,发送该事件
if (LOCAL_LOGD) Log.v(TAG, "Static IP configuration succeeded");
} else {
mHaveIpAddress = false;
event = EVENT_INTERFACE_CONFIGURATION_FAILED;
if (LOCAL_LOGD) Log.v(TAG, "Static IP configuration failed");
}
sendEmptyMessage(event);
}
}
case EVENT_INTERFACE_CONFIGURATION_SUCCEEDED:
/**
* Since this event is sent from another thread, it might have been
* sent after we closed our connection to the supplicant in the course
* of disabling Wi-Fi. In that case, we should just ignore the event.
*/
if (mWifiInfo.getSupplicantState() == SupplicantState.UNINITIALIZED) {
break;
}
mReconnectCount = 0;
mHaveIpAddress = true;
mObtainingIpAddress = false;
mWifiInfo.setIpAddress(mDhcpInfo.ipAddress);//设置IP地址
mLastSignalLevel = -1; // force update of signal strength
if (mNetworkInfo.getDetailedState() != DetailedState.CONNECTED) {
setDetailedState(DetailedState.CONNECTED);
sendNetworkStateChangeBroadcast(mWifiInfo.getBSSID());
} else {
msg = mTarget.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
msg.sendToTarget();
}
if (LOCAL_LOGD) Log.v(TAG, "IP configuration: " + mDhcpInfo);
// Wi-Fi interface configuration state changed:
// [31- 1] Reserved for future use
// [ 0- 0] Interface configuration succeeded (1) or failed (0)
EventLog.writeEvent(EVENTLOG_INTERFACE_CONFIGURATION_STATE_CHANGED, 1);
// We've connected successfully, so allow the notification again in the future
resetNotificationTimer();//连接成功,再次通知
break;
WifiStateTracker处理EVENT_DHCP_SUCCEEDED消息,成功设置IP地址。
结构部分分析到此为止,下节分析porting部分。