前言:
- Android wifi每次版本迭代与更新,除了框架在O版本有较大改变,往后的更新框架变化不大,但是还是有很多java文件名、调用流程变化还是不少。调用函数的名称还是能基本区分出来
- 前面我们梳理了wifi scan 及获取到scan数据后到app界面显示的流程,接下来就梳理下,从点击ap并输入连接信息的连接流程。
- wifistatemachine是wifi机制的核心
- wifiserviceImpl是wifi服务的管理者
流程梳理
点击想要连接的wifi后会调用这个函数:
WifiSettings.java
@Override
public boolean onPreferenceTreeClick(Preference preference) {
// If the preference has a fragment set, open that
if (preference.getFragment() != null) {
preference.setOnPreferenceClickListener(null);
return super.onPreferenceTreeClick(preference);
}
......
return true;
}
用户配置好之后点击连接按钮,你点击弹出框的确定按钮所要执行的代码,onClick函数会被调用:
WifiDialog.java
public void onClick(DialogInterface dialogInterface, int button) {
if (button == WifiDialog.BUTTON_FORGET && mSelected != null) {
forget(mSelected.networkId);
} else if (button == WifiDialog.BUTTON_SUBMIT && mDialog != null) {
WifiConfiguration config = mDialog.getConfig();
if (config == null) {
if (mSelected != null && !requireKeyStore(mSelected.getConfig())) {
connect(mSelected.networkId);
}
} else if (config.networkId != -1) {
if (mSelected != null) {
mWifiManager.updateNetwork(config);
saveNetworks();
}
} else {
int networkId = mWifiManager.addNetwork(config);
if (networkId != -1) {
mWifiManager.enableNetwork(networkId, false);
config.networkId = networkId;
if (mDialog.edit || requireKeyStore(config)) {
saveNetworks();
} else {
connect(networkId);
}
}
}
}
同样在WifiSettings.java中
@Override
public void onSubmit(WifiDialog dialog) {
if (mDialog != null) {
submit(mDialog.getController());
}
}
调用submit,在dialog完成ssid 以及密码填充后,到WifiManager save
void submit(WifiConfigController configController) {
final WifiConfiguration config = configController.getConfig();
if (config == null) {
if (mSelectedAccessPoint != null
&& mSelectedAccessPoint.isSaved()) {
connect(mSelectedAccessPoint.getConfig(), true /* isSavedNetwork */);
}
} else if (configController.getMode() == WifiConfigUiBase.MODE_MODIFY) {
mWifiManager.save(config, mSaveListener);
} else {
mWifiManager.save(config, mSaveListener);
if (mSelectedAccessPoint != null) {
// Not an "Add network"
connect(config, false /* isSavedNetwork */);
}
}
mWifiTracker.resumeScanning();
}
进行网络连接:
protected void connect(final WifiConfiguration config, boolean isSavedNetwork) {
// Log subtype if configuration is a saved network.
mMetricsFeatureProvider.action(getContext(), SettingsEnums.ACTION_WIFI_CONNECT,
isSavedNetwork);
mWifiManager.connect(config, mConnectListener);
mClickedConnect = true;
}
进入WifiManager的save函数:
WifiManager.java
public void save(WifiConfiguration config, ActionListener listener) {
getChannel().sendMessage(SAVE_NETWORK, 0, putListener(listener), config);
}
将SAVE_NETWORK 给到 WifiService的WifiServiceImpl
WifiServiceImpl.java
private class ClientHandler extends WifiHandler {
case WifiManager.SAVE_NETWORK:
{
mWifiStateMachine.sendMessage(Message.obtain(msg));
}
}
WifiServiceImpl又将 SAVE_NETWORK 送到中级cmd处理站:WifiStateMachine
WifiStateMachine
WifiStateMachine内部发送命令CMD_START_CONNECT命令到内部状态机:ConnectModeState处理,
private boolean connectToUserSelectNetwork(int netId, int uid, boolean forceReconnect) {
logd("connectToUserSelectNetwork netId " + netId + ", uid " + uid
+ ", forceReconnect = " + forceReconnect);
if (mWifiConfigManager.getConfiguredNetwork(netId) == null) {
loge("connectToUserSelectNetwork Invalid network Id=" + netId);
return false;
}
if (!mWifiConfigManager.enableNetwork(netId, true, uid)
|| !mWifiConfigManager.updateLastConnectUid(netId, uid)) {
logi("connectToUserSelectNetwork Allowing uid " + uid
+ " with insufficient permissions to connect=" + netId);
} else if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
// Note user connect choice here, so that it will be considered in the next network
// selection.
mWifiConnectivityManager.setUserConnectChoice(netId);
}
if (!forceReconnect && mWifiInfo.getNetworkId() == netId) {
// We're already connected to the user specified network, don't trigger a
// reconnection unless it was forced.
logi("connectToUserSelectNetwork already connecting/connected=" + netId);
} else {
mWifiConnectivityManager.prepareForForcedConnection(netId);
startConnectToNetwork(netId, uid, SUPPLICANT_BSSID_ANY);
}
return true;
}
public void startConnectToNetwork(int networkId, int uid, String bssid) {
sendMessage(CMD_START_CONNECT, networkId, uid, bssid);
}
接着送到WifiNative 进行处理Connect。
class ConnectModeState extends State {
case WifiManager.SAVE_NETWORK:
startConnectToNetwork(netId, message.sendingUid, SUPPLICANT_BSSID_ANY);// 连接热点
case CMD_START_CONNECT:
mWifiNative.connectToNetwork(mInterfaceName, config); // 转到wifiNative 进行connect
}
WifiNative
public boolean connectToNetwork(@NonNull String ifaceName, WifiConfiguration configuration) {
// Abort ongoing scan before connect() to unblock connection request.
mWificondControl.abortScan(ifaceName);
return mSupplicantStaIfaceHal.connectToNetwork(ifaceName, configuration);
}
接着就到了SupplicantStaIfaceHal ,
SupplicantStaIfaceHal
public boolean connectToNetwork(@NonNull String ifaceName, @NonNull WifiConfiguration config) {
synchronized (mLock) {
logd("connectToNetwork " + config.configKey());
WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
if (WifiConfigurationUtil.isSameNetwork(config, currentConfig)) {
String networkSelectionBSSID = config.getNetworkSelectionStatus()
.getNetworkSelectionBSSID();
String networkSelectionBSSIDCurrent =
currentConfig.getNetworkSelectionStatus().getNetworkSelectionBSSID();
if (Objects.equals(networkSelectionBSSID, networkSelectionBSSIDCurrent)) {
logd("Network is already saved, will not trigger remove and add operation.");
} else {
logd("Network is already saved, but need to update BSSID.");
if (!setCurrentNetworkBssid(
ifaceName,
config.getNetworkSelectionStatus().getNetworkSelectionBSSID())) {
loge("Failed to set current network BSSID.");
return false;
}
mCurrentNetworkLocalConfigs.put(ifaceName, new WifiConfiguration(config));
}
} else {
mCurrentNetworkRemoteHandles.remove(ifaceName);
mCurrentNetworkLocalConfigs.remove(ifaceName);
if (!removeAllNetworks(ifaceName)) {
loge("Failed to remove existing networks");
return false;
}
Pair<SupplicantStaNetworkHal, WifiConfiguration> pair =
addNetworkAndSaveConfig(ifaceName, config);
if (pair == null) {
loge("Failed to add/save network configuration: " + config.configKey());
return false;
}
mCurrentNetworkRemoteHandles.put(ifaceName, pair.first);
mCurrentNetworkLocalConfigs.put(ifaceName, pair.second);
}
SupplicantStaNetworkHal networkHandle =
checkSupplicantStaNetworkAndLogFailure(ifaceName, "connectToNetwork");
if (networkHandle == null || !networkHandle.select()) {
loge("Failed to select network configuration: " + config.configKey());
return false;
}
return true;
}
}
public void onStateChanged(int newState, byte[/* 6 */] bssid, int id,ArrayList<Byte> ssid) {
if (newSupplicantState == SupplicantState.COMPLETED){
mWifiMonitor.broadcastNetworkConnectionEvent(mIfaceName, getCurrentNetworkId(mIfaceName), bssidStr);
}
}
其中select函数在SupplicantStaNetworkHal中
SupplicantStaNetworkHal
//Trigger a connection to this network.
public boolean select() {
synchronized (mLock) {
final String methodStr = "select";
if (!checkISupplicantStaNetworkAndLogFailure(methodStr)) return false;
try {
SupplicantStatus status = mISupplicantStaNetwork.select();
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
return false;
}
}
}
- SupplicantStaIfaceHal 添加网络,执行select函数,通过hidl调用到supplicant,也就是 将connect 传给到 wpa_supplicant
sta_network
Return<void> StaNetwork::select(select_cb _hidl_cb)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
&StaNetwork::selectInternal, _hidl_cb);
}
SupplicantStatus StaNetwork::selectInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (wpa_ssid->disabled == 2) {
return {
SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
wpa_s->scan_min_time.sec = 0;
wpa_s->scan_min_time.usec = 0;
// Make sure that the supplicant is updated to the latest
// MAC address, which might have changed due to MAC randomization.
wpa_supplicant_update_mac_addr(wpa_s);
wpa_supplicant_select_network(wpa_s, wpa_ssid);
return {
SupplicantStatusCode::SUCCESS, ""};
}
- wpa_supplicant完成一系列与路由器的之间的beacon帧(probe、assoc、4way-handshake 、group-handshake)后,再能取到路由器的颁发的认可证(既是拿到最后的compelted)
- 最后,通过wifiMonitor上报wpa_supplicant 任务已完成,既是完成连接的第一阶段(连接阶段)
- WiFiMonitor上报的事件是NETWORK_CONNECTION_EVENT (又一次回到WifiStateMachine)
wpa_supplicant进行连接并调用底层最后回到wifiMonitor
wifiMonitor上报NETWORK_CONNECTION_EVENT给WifiStateMachine,在WifiStateMachine中获取ip:
WifiStateMachine
class ConnectModeState extends State {
case WifiMonitor.NETWORK_CONNECTION_EVENT:
....
sendNetworkStateChangeBroadcast(mLastBssid);
transitionTo(mObtainingIpState);
}
class ObtainingIpState extends State {
...
setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
clearTargetBssid("ObtainingIpAddress");
stopIpClient();
mIpClient.setHttpProxy(currentConfig.getHttpProxy());
IpClient.buildProvisioningConfiguration();
....
}
从Android N 后,获取IP已废弃了dhcpd,由IpClient 、IpManager来处理ip
连接流程还是在WifiStateMachine里
虽然最近的几个版本的安卓系统有些差异,但是根据自己的代码还是能梳理出来,有点耐心,注意细心,流程就自己画一个吧,相信上面的流程图已经很清楚了