Android WiFi的断开分析
1.wifi断开大体流程:
1.wifi断开 wlan-driver最先知道。
2.wlan-driver在与路由器连接的时候(未断开时), 会有周期性的beacon帧来维持连接,AP端一旦遇到突发事情,会立刻通过802.11协议的 deauth 帧/ reject 帧等 通知到 driver。
3. wlan-driver一旦收到802协议的 deauth帧/reject帧等后,马上断开与AP的连接。
4. 紧接着,wlan-driver的上层WifiStateMachine内部广播通知系统外部网络环境,系统跟Settings开始同步处理此次的断开。
2.wifi断开原因
3.wifi断开流程
4.代码流程
1. wpa_supplicant 部分
- wpa_driver_nl80211_drv_init 其核心完成与drv通道绑定(既是与driver建立好暗号信息交流通道),一旦有变化及时通风报信
- nl80211_init_bss 埋下的是第一步棋,监听解读 bss 802.11 数据帧
- process_bss_event 专门处理 802.11 数据帧,将之送往到 mlme_event 处理,mlme 完成分拣之后,装往 wpa_supplicant_event 大车上
- wpa_supplicant_event 大车把每个event送到对应得cmd中心处理站,进行卸货进一步分发处理,处理完成后通过 wpas_notify_state_changed 上报给 wpas_hidl_notify_state_changed
- wpas_hidl_notify_state_changed 完成接力赛最后一棒,将事件上报给到 SupplicantStaIfaceHal
- 这里,断开的所有原因(将在 wpa_supplicant_event 函数里可以找到),结合 driver行为和空中包
external/wpa_supplicant_8/hostapd/src/drivers/driver_nl80211.c
static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,void *global_priv, int hostapd,const u8 *set_addr,
const char *driver_params){
if (nl80211_init_bss(bss))
goto failed;
}
static int nl80211_init_bss(struct i802_bss *bss)
{
...
nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,process_bss_event, bss);
}
external/wpa_supplicant_8/src/drivers/driver_nl80211_event.c
int process_bss_event(struct nl_msg *msg, void *arg)
{
switch (gnlh->cmd) {
case NL80211_CMD_FRAME:
case NL80211_CMD_FRAME_TX_STATUS:
mlme_event(bss, gnlh->cmd, tb[NL80211_ATTR_FRAME],
tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
tb[NL80211_ATTR_COOKIE],
tb[NL80211_ATTR_RX_SIGNAL_DBM],
tb[NL80211_ATTR_STA_WME]);
break;
}
external/wpa_supplicant_8/wpa_supplicant/events.c
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,union wpa_event_data *data)
{
case EVENT_AUTH:
case ....
...
}
wpa_supplicant_set_state --wpa_supplicant.c
wpas_notify_state_changed -- hidi_manager.cpp
wpas_hidl_notify_state_changed -- hidl.cpp
2.wpa_supplicant --> hidl --> SupplicantStaIfaceHal
- wpa_supplicant 把接力棒交给了 wpa_supplicant 下面的 hidl.cpp,由他来完成事件的上报以及通知WifiMonitor
- 仍然是老套路,自从Android的版本升级之后,cpp与java之间的通信也是在不断地变化,从之前的aidl到现在的hidl,总是在变
- SupplicantStaIfaceHal 收到上报事件之后,通过这一长期合作伙伴WifiMonitor,将消息通知到系统各个模块
external/wpa_supplicant_8/wpa_supplicant/hidl/1.1/hidl.cpp
{
....
hidl_manager->notifyStateChange(wpa_s);
}
external/wpa_supplicant_8/wpa_supplicant/hidl/1.0/hidl_manager.cpp
{
....
callWithEachStaIfaceCallback(
wpa_s->ifname, std::bind(
&ISupplicantStaIfaceCallback::onStateChanged,
std::placeholders::_1,
static_cast<ISupplicantStaIfaceCallback::State>(
wpa_s->wpa_state),
bssid, hidl_network_id, hidl_ssid));
}
frameworks/opt/net/wifi/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java
public void onStateChanged(int newState, byte[/* 6 */] bssid, int id,ArrayList<Byte> ssid) {
mWifiMonitor.broadcastSupplicantStateChangeEvent( mIfaceName,
getCurrentNetworkId(mIfaceName), wifiSsid, bssidStr, newSupplicantState);
}
3.WifiMonitor --> WifiStateMachine --> 广播通知系统
- WifiMonitor 传输 SUPPLICANT_STATE_CHANGE_EVENT cmd 给到 WifiStateMachine
- WifiStateMachine 是 cmd 核心处理枢纽,每个 wifi 相关的 cmd 都会送到这里被分发执行
- 这里重点有DisconnectingState与 ConnectModeState 状态机,将会根据 wpa_supplicant 所处的状态 (disconnect 或者 completed 状态),处理行为不一样
- 如为 disconnect, 则转到 handleNetworkDisconnect(); 处理;如为 completed,则开启 ip gaining
- 最后,发送广播 WifiManager.NETWORK_STATE_CHANGED_ACTION , 通知wifi状态变化了,处理同步断开的状态flow
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiMonitor.java
public void broadcastSupplicantStateChangeEvent(String iface, int networkId, WifiSsid wifiSsid,....)
{
sendMessage(iface, SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,new StateChangeResult(networkId, wifiSsid, bssid, newSupplicantState));
}
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java
class ConnectModeState extends State {
{
.....
case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
SupplicantState state = handleSupplicantStateChange(message);
if (state == SupplicantState.DISCONNECTED
&& mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
if (mVerboseLoggingEnabled) {
log("Missed CTRL-EVENT-DISCONNECTED, disconnect");
}
handleNetworkDisconnect();
transitionTo(mDisconnectedState);
}
if (state == SupplicantState.COMPLETED) {
mIpClient.confirmConfiguration();
mWifiScoreReport.noteIpCheck();
}
}
class DisconnectingState extends State {
case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
handleNetworkDisconnect();
transitionTo(mDisconnectedState);
}