当用户选择一个活跃的AP时,WifiSettings响应打开一个对话框来配置AP,比如加密方法和连接AP的验证模式。配置好AP后,WifiService添加或更新网络连接到特定的AP。代码在wifisettings.java中:
public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
if (preference instanceof AccessPoint) {
mSelectedAccessPoint = (AccessPoint) preference;
/** Bypass dialog for unsecured, unsaved networks */
if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE &&
mSelectedAccessPoint.networkId == INVALID_NETWORK_ID) {
mSelectedAccessPoint.generateOpenNetworkConfig();
mWifiManager.connectNetwork(mSelectedAccessPoint.getConfig());
} else {
showConfigUi(mSelectedAccessPoint, false);
}
} else {
return super.onPreferenceTreeClick(screen, preference);
}
return true;
}
调用showConfigUi(mSelectedAccessPoint, false);在屏幕上显示配置界面:
private void showConfigUi(AccessPoint accessPoint, boolean edit) {
if (mInXlSetupWizard) {
((WifiSettingsForSetupWizardXL)getActivity()).showConfigUi(accessPoint, edit);
} else {
showDialog(accessPoint, edit);
}
}
然后调用showDialog(accessPoint, edit):
private void showDialog(AccessPoint accessPoint, boolean edit) {
if (mDialog != null) {
removeDialog(WIFI_DIALOG_ID);
mDialog = null;
}
// Save the access point and edit mode
mDlgAccessPoint = accessPoint;
mDlgEdit = edit;
showDialog(WIFI_DIALOG_ID);
}
然后通过WIFI_DIALOG_ID来创建该对话框:
public Dialog onCreateDialog(int dialogId) {
AccessPoint ap = mDlgAccessPoint; // For manual launch
if (ap == null) { // For re-launch from saved state
if (mAccessPointSavedState != null) {
ap = new AccessPoint(getActivity(), mAccessPointSavedState);
// For repeated orientation changes
mDlgAccessPoint = ap;
}
}
// If it's still null, fine, it's for Add Network
mSelectedAccessPoint = ap;
mDialog = new WifiDialog(getActivity(), this, ap, mDlgEdit);
return mDialog;
}
这样配置ap密码的对话框就完成了。
当用户配置好之后点击连接时会调用onClick函数:
public void onClick(DialogInterface dialogInterface, int button) {
if (mInXlSetupWizard) {
if (button == WifiDialog.BUTTON_FORGET && mSelectedAccessPoint != null) {
forget();
} else if (button == WifiDialog.BUTTON_SUBMIT) {
((WifiSettingsForSetupWizardXL)getActivity()).onConnectButtonPressed();
}
} else {
if (button == WifiDialog.BUTTON_FORGET && mSelectedAccessPoint != null) {
forget();
} else if (button == WifiDialog.BUTTON_SUBMIT) {
submit(mDialog.getController());
}
}
}
然后调用submit(mDialog.getController())函数进行提交:
void submit(WifiConfigController configController) {
int networkSetup = configController.chosenNetworkSetupMethod();
switch(networkSetup) {
case WifiConfigController.WPS_PBC:
case WifiConfigController.WPS_DISPLAY:
case WifiConfigController.WPS_KEYPAD:
mWifiManager.startWps(configController.getWpsConfig());
break;
case WifiConfigController.MANUAL:
final WifiConfiguration config = configController.getConfig();
if (config == null) {
if (mSelectedAccessPoint != null
&& !requireKeyStore(mSelectedAccessPoint.getConfig())
&& mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {
mWifiManager.connectNetwork(mSelectedAccessPoint.networkId);
}
} else if (config.networkId != INVALID_NETWORK_ID) {
if (mSelectedAccessPoint != null) {
saveNetwork(config);
}
} else {
if (configController.isEdit() || requireKeyStore(config)) {
saveNetwork(config);
} else {
mWifiManager.connectNetwork(config);
}
}
break;
}
if (mWifiManager.isWifiEnabled()) {
mScanner.resume();
}
updateAccessPoints();
}
然后调用mWifiManager.connectNetwork(mSelectedAccessPoint.networkId);函数进行连接:
public void connectNetwork(int networkId) {
if (networkId < 0) {
return;
}
mAsyncChannel.sendMessage(CMD_CONNECT_NETWORK, networkId);
}
发送了一个CMD_CONNECT_NETWORK消息,在wifiservice中:
case WifiManager.CMD_CONNECT_NETWORK: {
if (msg.obj != null) {
mWifiStateMachine.connectNetwork((WifiConfiguration)msg.obj);
} else {
mWifiStateMachine.connectNetwork(msg.arg1);
}
break;
}
处理该消息,调用mWifiStateMachine.connectNetwork((WifiConfiguration)msg.obj):
public void connectNetwork(WifiConfiguration wifiConfig) {
/* arg1 is used to indicate netId, force a netId value of
* WifiConfiguration.INVALID_NETWORK_ID when we are passing
* a configuration since the default value of 0 is a valid netId
*/
sendMessage(obtainMessage(CMD_CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,
0, wifiConfig));
}
发送了一个消息,在ConnectModeState状态处理该消息:
case CMD_CONNECT_NETWORK:
int netId = message.arg1;
WifiConfiguration config = (WifiConfiguration) message.obj;
/* We connect to a specific network by issuing a select
* to the WifiConfigStore. This enables the network,
* while disabling all other networks in the supplicant.
* Disabling a connected network will cause a disconnection
* from the network. A reconnectCommand() will then initiate
* a connection to the enabled network.
*/
if (config != null) {
netId = WifiConfigStore.selectNetwork(config);
} else {
WifiConfigStore.selectNetwork(netId);
}
/* The state tracker handles enabling networks upon completion/failure */
mSupplicantStateTracker.sendMessage(CMD_CONNECT_NETWORK);
WifiNative.reconnectCommand();
mLastExplicitNetworkId = netId;
mLastNetworkChoiceTime = SystemClock.elapsedRealtime();
mNextWifiActionExplicit = true;
if (DBG) log("Setting wifi connect explicit for netid " + netId);
/* Expect a disconnection from the old connection */
transitionTo(mDisconnectingState);
break;
调用WifiConfigStore.selectNetwork(netId):
static void selectNetwork(int netId) {
// Reset the priority of each network at start or if it goes too high.
if (sLastPriority == -1 || sLastPriority > 1000000) {
synchronized (sConfiguredNetworks) {
for(WifiConfiguration config : sConfiguredNetworks.values()) {
if (config.networkId != INVALID_NETWORK_ID) {
config.priority = 0;
addOrUpdateNetworkNative(config);
}
}
}
sLastPriority = 0;
}
// Set to the highest priority and save the configuration.
WifiConfiguration config = new WifiConfiguration();
config.networkId = netId;
config.priority = ++sLastPriority;
addOrUpdateNetworkNative(config);
WifiNative.saveConfigCommand();
/* Enable the given network while disabling all other networks */
enableNetworkWithoutBroadcast(netId, true);
/* Avoid saving the config & sending a broadcast to prevent settings
* from displaying a disabled list of networks */
}
重新设置各network的优先级,关闭其他网络,打开该网络。
addOrUpdateNetworkNative(config)添加网络。
WifiNative.saveConfigCommand():保存该网络。
调用enableNetworkWithoutBroadcast(netId, true)打开用户选择的网络,关闭其他网络:
static boolean enableNetworkWithoutBroadcast(int netId, boolean disableOthers) {
boolean ret = WifiNative.enableNetworkCommand(netId, disableOthers);
synchronized (sConfiguredNetworks) {
WifiConfiguration config = sConfiguredNetworks.get(netId);
if (config != null) config.status = Status.ENABLED;
}
if (disableOthers) {
markAllNetworksDisabledExcept(netId);
}
return ret;
}
调用JNI函数WifiNative.enableNetworkCommand,打开选定网络关闭其他的网络,同步更改各网络的状态。
发送消息mSupplicantStateTracker.sendMessage(CMD_CONNECT_NETWORK)处理正在打开的网络:
class DefaultState extends State {
case WifiStateMachine.CMD_CONNECT_NETWORK:
mNetworksDisabledDuringConnect = true;
break;
然后切换到mDisconnectingState状态。
Ip地址的配置:
当wpa_supplicant连接到ap之后会向上层发送一个CONNECTED 事件,wifimonitor接收到该事件后:
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:
mStateMachine.sendMessage(SCAN_RESULTS_EVENT);
break;
case UNKNOWN:
break;
}
}
调用handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder)函数:
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 (false) 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;
}
}
}
notifyNetworkStateChange(newState, BSSID, networkId);
}
之后调用notifyNetworkStateChange(newState, BSSID, networkId):
void notifyNetworkStateChange(NetworkInfo.DetailedState newState, String BSSID, int netId) {
if (newState == NetworkInfo.DetailedState.CONNECTED) {
Message m = mStateMachine.obtainMessage(NETWORK_CONNECTION_EVENT,
netId, 0, BSSID);
mStateMachine.sendMessage(m);
} else {
Message m = mStateMachine.obtainMessage(NETWORK_DISCONNECTION_EVENT,
netId, 0, BSSID);
mStateMachine.sendMessage(m);
}
}
向wifi状态机发送消息: Message m = mStateMachine.obtainMessage(NETWORK_CONNECTION_EVENT,
netId, 0, BSSID);
在wifistateMachine.java中ConnectModeState 状态处理该消息:
case WifiMonitor.NETWORK_CONNECTION_EVENT:
if (DBG) log("Network connection established");
mLastNetworkId = message.arg1;
mLastBssid = (String) message.obj;
//TODO: make supplicant modification to push this in events
mWifiInfo.setSSID(fetchSSID());
mWifiInfo.setBSSID(mLastBssid);
mWifiInfo.setNetworkId(mLastNetworkId);
if (mNextWifiActionExplicit &&
mWifiInfo.getNetworkId() == mLastExplicitNetworkId &&
SystemClock.elapsedRealtime() < mLastNetworkChoiceTime +
EXPLICIT_CONNECT_ALLOWED_DELAY_MS) {
mWifiInfo.setExplicitConnect(true);
}
mNextWifiActionExplicit = false;
/* send event to CM & network change broadcast */
setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
sendNetworkStateChangeBroadcast(mLastBssid);
transitionTo(mConnectingState);
break;
设置ssid等,然后切换到ConnectingState状态启动DHCP分配ip:
class ConnectingState extends State {
@Override
public void enter() {
if (DBG) log(getName() + "\n");
EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
try {
mNwService.enableIpv6(mInterfaceName);
} catch (RemoteException re) {
loge("Failed to enable IPv6: " + re);
} catch (IllegalStateException e) {
loge("Failed to enable IPv6: " + e);
}
if (!WifiConfigStore.isUsingStaticIp(mLastNetworkId)) { //判断是使用静态IP还是动态分配
//start DHCP
mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(
mContext, WifiStateMachine.this, mInterfaceName);
mDhcpStateMachine.registerForPreDhcpNotification();// 开启预分配
mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);//向DHCP状态机发送开始命令
} else {
DhcpInfoInternal dhcpInfoInternal = WifiConfigStore.getIpConfiguration(
mLastNetworkId);
InterfaceConfiguration ifcg = new InterfaceConfiguration();
ifcg.addr = dhcpInfoInternal.makeLinkAddress();
ifcg.interfaceFlags = "[up]";
try {
mNwService.setInterfaceConfig(mInterfaceName, ifcg);
if (DBG) log("Static IP configuration succeeded");
sendMessage(CMD_STATIC_IP_SUCCESS, dhcpInfoInternal);
} 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);
}
}
}
在DhcpStateMachine.javs中:dhcp状态机的初始状态是StoppedState,该状态处理CMD_START_DHCP消息:
class StoppedState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
}
@Override
public boolean processMessage(Message message) {
boolean retValue = HANDLED;
if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
switch (message.what) {
case CMD_START_DHCP:
if (mRegisteredForPreDhcpNotification) {
/* Notify controller before starting DHCP */
mController.sendMessage(CMD_PRE_DHCP_ACTION);
transitionTo(mWaitBeforeStartState);
} else {
if (runDhcp(DhcpAction.START)) {
transitionTo(mRunningState);
}
}
break;
发送mController.sendMessage(CMD_PRE_DHCP_ACTION)消息,然后切换到 (mWaitBeforeStartState)状态, wifi状态机中ConnectingState状态接收该消息并处理:
case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
handlePreDhcpSetup();
mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
break;
处理完分配地址前的一些操作,通知dhcp完成预分配mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE),dhcp当前状态WaitBeforeStartState接收该消息并处理:
case CMD_PRE_DHCP_ACTION_COMPLETE:
if (runDhcp(DhcpAction.START)) {
transitionTo(mRunningState);
} else {
transitionTo(mStoppedState);
}
break;
调用runDhcp开始分配ip地址,然后切换到mRunningState状态。在runDhcp函数中
调用NetworkUtils.runDhcp函数来分配ip地址:
if (dhcpAction == DhcpAction.START) {
if (DBG) Log.d(TAG, "DHCP request on " + mInterfaceName);
success = NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal);
mDhcpInfo = dhcpInfoInternal;
分配的ip地址和dns放在DhcpInfoInternal类中。