Andriod P之connect wifi

前言:

  • 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里
虽然最近的几个版本的安卓系统有些差异,但是根据自己的代码还是能梳理出来,有点耐心,注意细心,流程就自己画一个吧,相信上面的流程图已经很清楚了

猜你喜欢

转载自blog.csdn.net/weixin_42271802/article/details/112193257