Wifi连接一个ap一般有两种方式:长按一个网络然后弹出一个菜单,选择连接网络(或者对于已经保存网络也是单击弹出菜单点击连接menu);另一种点击一个网络,然后弹出一个Dialog,输入密码再进行连接。两种方式的连接在底层并无区别,但是在应用层的逻辑略有不同。
首先我们先来罗列上层应用连接的流程。
在梳理流程中,对于与流程相关性不大的代码省略,否则篇幅就会过长,读者可以参照代码路径和方法名找到方法的具体实现。
Wifi连接使用Dialog
/android/packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java:
public boolean onPreferenceTreeClick(Preference preference) {
//连接到开放网络(无密码)
case WifiUtils.CONNECT_TYPE_OPEN_NETWORK:
//连接到已保存的网络
case WifiUtils.CONNECT_TYPE_SAVED_NETWORK:
//都不是(没连过的)
default:
showDialog(mSelectedAccessPoint, WifiConfigUiBase.MODE_CONNECT);
}
private void showDialog(AccessPoint accessPoint, int dialogMode) {
// Save the access point and edit mode
mDlgAccessPoint = accessPoint;
mDialogMode = dialogMode;
showDialog(WIFI_DIALOG_ID);
}
public Dialog onCreateDialog(int dialogId) {
case WIFI_DIALOG_ID:
//创建一个Dialog
mDialog = WifiDialog.createModal(getActivity(), this, mDlgAccessPoint, mDialogMode);
return mDialog;
}
在Dialog中进行操作
/android/packages/apps/Settings/src/com/android/settings/wifi/WifiDialog.java:
public void onClick(DialogInterface dialogInterface, int id) {
if (mListener != null) {
switch (id) {
case BUTTON_SUBMIT:
mListener.onSubmit(this);
break;
case BUTTON_FORGET:
}
}
}
/android/packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java:
@Override
public void onSubmit(WifiDialog dialog) {
if (mDialog != null) {
submit(mDialog.getController());
}
}
void submit(WifiConfigController configController) {
mWifiManager.save(config, mSaveListener);
if (mSelectedAccessPoint != null) { // Not an "Add network"
connect(config, false /* isSavedNetwork */);
}
mWifiTracker.resumeScanning();//触发扫描
}
connect()方法就开始连接了。。。
Wifi连接使用Menu
还是从WifiSettings界面开始
/android/packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java:
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) {
if (mSelectedAccessPoint.isConnectable()) {
menu.add(Menu.NONE, MENU_ID_CONNECT, 0 /* order */, R.string.wifi_connect);
}
}
@Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_ID_CONNECT: {
connect(mSelectedAccessPoint.getConfig(), isSavedNetwork);
}
}
}
上述两种方法最后都调用到了WifiSettings.java的connect方法,那么接下来就从connect开始分析连接流程。
Wifi连接后续流程
/android/packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java:
protected void connect(final WifiConfiguration config, boolean isSavedNetwork) {
mWifiManager.connect(config, mConnectListener);
}
/android/frameworks/base/wifi/java/android/net/wifi/WifiManager.java:
public void connect(@NonNull WifiConfiguration config, @Nullable ActionListener listener) {
getChannel().sendMessage(CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID, putListener(listener), config);
}
public void save(@NonNull WifiConfiguration config, @Nullable ActionListener listener) {
getChannel().sendMessage(SAVE_NETWORK, 0, putListener(listener), config);
}
connect方法发送了CONNECT_NETWORK和SAVE_NETWORK消息,WifiServiceImpl.java关注这些消息。
/android/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java:
case WifiManager.SAVE_NETWORK: {
else if (config != null) {
//将消息转发至状态机 */
mClientModeImpl.sendMessage(Message.obtain(msg));
case WifiManager.CONNECT_NETWORK:
else if (config != null) {
//将消息转发至状态机 */
mClientModeImpl.sendMessage(Message.obtain(msg));
/android/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeImpl.java:
ClientModeImpl是一个状态机,在WIFI打开之后,其处于ConnectModeState,所以在此状态下处理消息。
class ConnectModeState extends State {
case WifiManager.SAVE_NETWORK:
startConnectToNetwork(netId, message.sendingUid, SUPPLICANT_BSSID_ANY);
case WifiManager.CONNECT_NETWORK:
public void startConnectToNetwork(int networkId, int uid, String bssid) {
sendMessage(CMD_START_CONNECT, networkId, uid, bssid);
}
保存成功之后,就去连接,还是处于ConnectModeState来处理消息。
case CMD_START_CONNECT:
if (mWifiNative.connectToNetwork(mInterfaceName, config)) {
。。。
if (getCurrentState() != mDisconnectedState) {
**transitionTo(mDisconnectingState);**
}
}
/android/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java:
public boolean connectToNetwork(@NonNull String ifaceName, WifiConfiguration configuration) {
mSupplicantStaIfaceHal.connectToNetwork(ifaceName, configuration);
}
/android/frameworks/opt/net/wifi/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java:
public boolean connectToNetwork(@NonNull String ifaceName, @NonNull WifiConfiguration config) {
addNetworkAndSaveConfig(ifaceName, config);
}
private Pair<SupplicantStaNetworkHal, WifiConfiguration>addNetworkAndSaveConfig(@NonNull String ifaceName, WifiConfiguration config) {
SupplicantStaNetworkHal network = addNetwork(ifaceName);//添加一个新的网络
}
//注册回调
public void onVendorStateChanged(int newState, byte[/* 6 */] bssid, int id, ArrayList<Byte> ssid, boolean filsHlpSent) {
mWifiMonitor.broadcastSupplicantStateChangeEvent(mIfaceName, getCurrentNetworkId(mIfaceName), wifiSsid, bssidStr, newSupplicantState);
}
/android/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiMonitor.java:
public void broadcastFilsNetworkConnectionEvent(String iface, int networkId, String bssid) {
sendMessage(iface, FILS_NETWORK_CONNECTION_EVENT, networkId, 0, bssid);
}
/android/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeImpl.java:
关注此消息,此时处于DisconnectingState。
case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
deferMessage(message);
transitionTo(mDisconnectedState);
接着状态转变到DisconnectedState
class DisconnectedState extends State {
case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
//向上层通知wifi状态
setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
/* ConnectModeState完成后续处理 */
handleStatus = NOT_HANDLED;
break;
所以又回到ConnectModeState。
case WifiMonitor.FILS_NETWORK_CONNECTION_EVENT:
case WifiMonitor.NETWORK_CONNECTION_EVENT:
sendNetworkStateChangeBroadcast(mLastBssid);
transitionTo(mObtainingIpState);
进入mObtainingIpState。
class ObtainingIpState extends State {
public void enter(){
mIpClient.startProvisioning(prov);
}
/android/frameworks/base/packages/NetworkStack/src/android/net/ip/IpClient.java:
public void startProvisioning(ProvisioningConfiguration req) {
mCallback.setNeighborDiscoveryOffload(true);
sendMessage(CMD_START, new android.net.shared.ProvisioningConfiguration(req));
}
IpClient拥有四个状态,其初始状态是StoppedState。
class StoppedState extends State {
case CMD_START:
transitionTo(mStartedState);
class StartedState extends State {
public void enter() {
deferMessage(obtainMessage(CMD_JUMP_STARTED_TO_RUNNING));
}
}
自己发送消息,自己处理
case CMD_JUMP_STARTED_TO_RUNNING:
transitionTo(mRunningState);
切换到RunningState
class RunningState extends State {
if (mConfiguration.mEnableIPv6 && !startIPv6()) {
。。。
}
if (mConfiguration.mEnableIPv4 && !startIPv4()) {
。。。
}
private boolean startIPv4() {
//先进状态机,让状态机处于初始化状态
mDhcpClient = DhcpClient.makeDhcpClient(mContext, IpClient.this, mInterfaceParams);
//然后向状态机发送消息,让其处理
mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP);
}
/android/frameworks/base/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java:
进入状态机,其初始状态为mStoppedState。
class StoppedState extends State {
case CMD_START_DHCP:
if (mRegisteredForPreDhcpNotification) {//=true
transitionTo(mWaitBeforeStartState);
}
}
切换状态到
class WaitBeforeStartState extends WaitBeforeOtherState {
public WaitBeforeStartState(State otherState) {
super();
mOtherState = otherState;
}
由于上述方法又super(),所以执行其父类状态enter
abstract class WaitBeforeOtherState extends LoggingState {
public void enter() {
super.enter();
mController.sendMessage(CMD_PRE_DHCP_ACTION);
}
}
发送了CMD_PRE_DHCP_ACTION消息,ClientModeImpl.java处理此消息,此前处于mObtainingIpState状态,由于此状态没有对应处理,所以
/android/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeImpl.java:
default:
handleStatus = NOT_HANDLED;//消息交由其父状态mL2ConnectedState来处理
break;
class L2ConnectedState extends State {
case CMD_PRE_DHCP_ACTION:
handlePreDhcpSetup();
break;
}
void handlePreDhcpSetup() {
sendMessage(CMD_PRE_DHCP_ACTION_COMPLETE);
}
再次回到:
/android/frameworks/base/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java:
//当前处于WaitBeforeOtherState
case CMD_PRE_DHCP_ACTION_COMPLETE:
transitionTo(mOtherState);//OtherState=mDhcpInitState
切换状态:
class DhcpInitState extends PacketRetransmittingState {
//接收数据包(开始是空的,因为要先主动发送数据包)
protected void receivePacket(DhcpPacket packet) {
transitionTo(mDhcpRequestingState);
}
}
进入父类enter
abstract class PacketRetransmittingState extends LoggingState {
public void enter() {
sendMessage(CMD_KICK);
}
}
case CMD_KICK:
sendPacket();//主动发数据包
scheduleKick();
return HANDLED;
切换状态:
class DhcpRequestingState extends PacketRetransmittingState {
/接收数据包
protected void receivePacket(DhcpPacket packet) {
setDhcpLeaseExpiry(packet);
acceptDhcpResults(results, "Confirmed");
transitionTo(mConfiguringInterfaceState);
}
//接收数据集
private void acceptDhcpResults(DhcpResults results, String msg) {
notifySuccess();
}
private void notifySuccess() {
mController.sendMessage(CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, new DhcpResults(mDhcpLease));
}