在 WifiConnectivityManager 中收到扫描结果进行处理,选择相应的网络进行连接,发生在 connectToNetwork 接口中:

    /*** Attempt to connect to a network candidate.** Based on the currently connected network, this menthod determines whether we should* connect or roam to the network candidate recommended by WifiNetworkSelector.*/private void connectToNetwork(WifiConfiguration candidate) {ScanResult scanResultCandidate = candidate.getNetworkSelectionStatus().getCandidate();if (scanResultCandidate == null) {localLog("connectToNetwork: bad candidate - "  + candidate+ " scanResult: " + scanResultCandidate);return;}String targetBssid = scanResultCandidate.BSSID;String targetAssociationId = candidate.SSID + " : " + targetBssid;// Check if we are already connected or in the process of connecting to the target// BSSID. mWifiInfo.mBSSID tracks the currently connected BSSID. This is checked just// in case the firmware automatically roamed to a BSSID different from what// WifiNetworkSelector selected.if (targetBssid != null&& (targetBssid.equals(mLastConnectionAttemptBssid)|| targetBssid.equals(mWifiInfo.getBSSID()))&& SupplicantState.isConnecting(mWifiInfo.getSupplicantState())) {localLog("connectToNetwork: Either already connected "+ "or is connecting to " + targetAssociationId);return;}if (candidate.BSSID != null&& !candidate.BSSID.equals(ClientModeImpl.SUPPLICANT_BSSID_ANY)&& !candidate.BSSID.equals(targetBssid)) {localLog("connecToNetwork: target BSSID " + targetBssid + " does not match the "+ "config specified BSSID " + candidate.BSSID + ". Drop it!");return;}long elapsedTimeMillis = mClock.getElapsedSinceBootMillis();if (!mScreenOn && shouldSkipConnectionAttempt(elapsedTimeMillis)) {localLog("connectToNetwork: Too many connection attempts. Skipping this attempt!");mTotalConnectivityAttemptsRateLimited++;return;}noteConnectionAttempt(elapsedTimeMillis);mLastConnectionAttemptBssid = targetBssid;WifiConfiguration currentConnectedNetwork = mConfigManager.getConfiguredNetwork(mWifiInfo.getNetworkId());String currentAssociationId = (currentConnectedNetwork == null) ? "Disconnected" :(mWifiInfo.getSSID() + " : " + mWifiInfo.getBSSID());if (currentConnectedNetwork != null&& (currentConnectedNetwork.networkId == candidate.networkId//TODO(b/36788683): re-enable linked configuration check/* || currentConnectedNetwork.isLinked(candidate) */)) {// Framework initiates roaming only if firmware doesn't support// {@link android.net.wifi.WifiManager#WIFI_FEATURE_CONTROL_ROAMING}.if (mConnectivityHelper.isFirmwareRoamingSupported()) {// Keep this logging here for now to validate the firmware roaming behavior.localLog("connectToNetwork: Roaming candidate - " + targetAssociationId + "."+ " The actual roaming target is up to the firmware.");} else {localLog("connectToNetwork: Roaming to " + targetAssociationId + " from "+ currentAssociationId);mStateMachine.startRoamToNetwork(candidate.networkId, scanResultCandidate);}} else {// Framework specifies the connection target BSSID if firmware doesn't support// {@link android.net.wifi.WifiManager#WIFI_FEATURE_CONTROL_ROAMING} or the// candidate configuration contains a specified BSSID.if (mConnectivityHelper.isFirmwareRoamingSupported() && (candidate.BSSID == null|| candidate.BSSID.equals(ClientModeImpl.SUPPLICANT_BSSID_ANY))) {targetBssid = ClientModeImpl.SUPPLICANT_BSSID_ANY;localLog("connectToNetwork: Connect to " + candidate.SSID + ":" + targetBssid+ " from " + currentAssociationId);} else {localLog("connectToNetwork: Connect to " + targetAssociationId + " from "+ currentAssociationId);}mStateMachine.startConnectToNetwork(candidate.networkId, Process.WIFI_UID, targetBssid);}}

总体来讲该函数获取当前的连接状态,包括已经配置的网络信息,与即将准备连接的网络进行对比,如果相同并且支持 roaming,则进行漫游连接操作,如果不同,进行连接操作,调用了 mStateMachine 的 startConnectToNetwork 方法进行连接

mStateMachine 实际上是 ClientModeImpl 类对象,在 WifiConnectivityManager 类对象初始化的时候传入,它是 ClientMode 的实现类,实现了 Client Mode 的事件处理逻辑,它是 StateMachine 的子类,连接方法非常简单,就是发送 CMD_START_CONNECT 消息进行连接:

    /*** Automatically connect to the network specified** @param networkId ID of the network to connect to* @param uid UID of the app triggering the connection.* @param bssid BSSID of the network*/public void startConnectToNetwork(int networkId, int uid, String bssid) {sendMessage(CMD_START_CONNECT, networkId, uid, bssid);}

CMD_START_CONNECT 消息在状态机中由两个状态会处理,分别是 DefaultState 和 ConnectModeState,他们之间的关系如下:

        addState(mDefaultState);addState(mConnectModeState, mDefaultState);addState(mL2ConnectedState, mConnectModeState);addState(mObtainingIpState, mL2ConnectedState);addState(mConnectedState, mL2ConnectedState);addState(mRoamingState, mL2ConnectedState);addState(mDisconnectingState, mConnectModeState);addState(mDisconnectedState, mConnectModeState);setInitialState(mDefaultState);

因此由 ConnectModeState 进行处理,截取其 processMessage 片段如下:

                case CMD_START_CONNECT:/* connect command coming from auto-join */netId = message.arg1;int uid = message.arg2;bssid = (String) message.obj;mSentHLPs = false;if (!hasConnectionRequests()) {if (mNetworkAgent == null) {loge("CMD_START_CONNECT but no requests and not connected,"+ " bailing");break;} else if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {loge("CMD_START_CONNECT but no requests and connected, but app "+ "does not have sufficient permissions, bailing");break;}}config = mWifiConfigManager.getConfiguredNetworkWithoutMasking(netId);logd("CMD_START_CONNECT "+ " my state " + getCurrentState().getName()+ " nid=" + Integer.toString(netId)+ " roam=" + Boolean.toString(mIsAutoRoaming));if (config == null) {loge("CMD_START_CONNECT and no config, bail out...");break;}mTargetNetworkId = netId;// Update scorecard while there is still state from existing connectionint scanRssi = mWifiConfigManager.findScanRssi(netId,mWifiHealthMonitor.getScanRssiValidTimeMs());mWifiScoreCard.noteConnectionAttempt(mWifiInfo, scanRssi, config.SSID);mBssidBlocklistMonitor.updateFirmwareRoamingConfiguration(config.SSID);updateWifiConfigOnStartConnection(config, bssid);reportConnectionAttemptStart(config, mTargetBssid,WifiMetricsProto.ConnectionEvent.ROAM_UNRELATED);String currentMacAddress = mWifiNative.getMacAddress(mInterfaceName);mWifiInfo.setMacAddress(currentMacAddress);Log.i(TAG, "Connecting with " + currentMacAddress + " as the mac address");mTargetWifiConfiguration = config;/* Check for FILS configuration again after updating the config */if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.FILS_SHA256)|| config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.FILS_SHA384)) {boolean isIpClientStarted = startIpClient(config, true);if (isIpClientStarted) {mIpClientWithPreConnection = true;break;}}connectToNetwork(config);break;

处理过程分析如下:

1. 判断是否存在连接请求,通过 hasConnectionRequests 方法,最终调用了 mNetworkFactory 和 mUntrackedNetworkFactory 的 hasConnectionRequests 方法进行判断,关于连接请求的添加另外分析;

2. 判断 mNetworkAgent 是否为空,NetworkAgent 是每个网络连接模块与系统网络管理模块交互的接口,对于 WiFi 连接,采用了 WifiNetworkAgent 类进行了封装,注册到系统中;

3. 获取当前 netId 对应的网络配置信息,该请求通过 WifiConfigManager 的 getConfiguredNetworkWithoutMasking 进行,而配置在什么地方如何设置到 Configuration 中在后面分析,这里如果没有查找到配置信息,则不会继续进行连接过程(网络配置的保存发生在调用 connectToNetwork 的 WifiConnectivityManager 类的回调 handleScanResults 中,在 connectToNetwork 之前调用,通过 NetworkSelector 类的 selectNetwork 方法,调用 updateChosenPasspointNetwork 方法,接着调用了 WifiConfigManager 的 addOrUpdateNetwork 方法将配置保存下来,内部调用了 addOrUpdateNetworkInternal 方法);

4. 回到 handleScanResults 处理过程,紧接着调用了 WifiConnectivityManager 中的 connectToNetwork,它内部继续调用了 mStateMachine 也就是 ClientModeImpl 类的 startConnectToNetwork 方法,其内部处理很简单,发出一个 CMD_START_CONNECT 消息由状态机进行处理,这里的处理过程发生在 ConnectModeState,在进行连接前更新配置息 updateWifiConfigOnStartConnection;

5. 通过 reportConnectionAttemptStart 方法通知系统其他组件网络开始进行连接;

6. 通过 startIpClient 启动 IP 配置功能,可能为 STATIC 或者 DHCP;

7. 通过 connectToNetwork 接口开始连接,代码如下:

    void connectToNetwork(WifiConfiguration config) {if ((config != null) && mWifiNative.connectToNetwork(mInterfaceName, config)) {mWifiInjector.getWifiLastResortWatchdog().noteStartConnectTime();mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_START_CONNECT, config);mLastConnectAttemptTimestamp = mClock.getWallClockMillis();mIsAutoRoaming = false;if (getCurrentState() != mDisconnectedState) {transitionTo(mDisconnectingState);}} else {loge("CMD_START_CONNECT Failed to start connection to network " + config);mTargetWifiConfiguration = null;stopIpClient();reportConnectionAttemptEnd(WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,WifiMetricsProto.ConnectionEvent.HLF_NONE,WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN);}}

处理过程较简单,判断 config 非空的情况下调用 WifiNative 的 connectToNetwork 进行连接,成功返回 true,然后更新时间戳和记录状态等,判断状态信息是否正确,如果当前不是处于 mDisconnectedState 则需要切换到该状态;而如果 WifiNative 的 connectToNetwork 返回了 false 则停止 IP 配置功能,记录状态信息。

WifiNative 的 connectToNetwork 如下:

    /*** Add the provided network configuration to wpa_supplicant and initiate connection to it.* This method does the following:* 1. Abort any ongoing scan to unblock the connection request.* 2. Remove any existing network in wpa_supplicant(This implicitly triggers disconnect).* 3. Add a new network to wpa_supplicant.* 4. Save the provided configuration to wpa_supplicant.* 5. Select the new network in wpa_supplicant.* 6. Triggers reconnect command to wpa_supplicant.** @param ifaceName Name of the interface.* @param configuration WifiConfiguration parameters for the provided network.* @return {@code true} if it succeeds, {@code false} otherwise*/public boolean connectToNetwork(@NonNull String ifaceName, WifiConfiguration configuration) {// Abort ongoing scan before connect() to unblock connection request.mWifiCondManager.abortScan(ifaceName);return mSupplicantStaIfaceHal.connectToNetwork(ifaceName, configuration);}

首先通过 WifiCondManager 的 abortScan 方法停止对应接口的扫描动作,然后调用 SupplicantStaIfaceHal 的 connectToNetwork 方法进行连接。abortScan 实际上调用到具体的 ScannerImpl 实现中对应的同名接口实现,SupplicantStaIfaceHal 的 connectToNetwork 方法如下:

    /*** Add the provided network configuration to wpa_supplicant and initiate connection to it.* This method does the following:* 1. If |config| is different to the current supplicant network, removes all supplicant* networks and saves |config|.* 2. Select the new network in wpa_supplicant.** @param ifaceName Name of the interface.* @param config WifiConfiguration parameters for the provided network.* @return {@code true} if it succeeds, {@code false} otherwise*/public boolean connectToNetwork(@NonNull String ifaceName, @NonNull WifiConfiguration config) {synchronized (mLock) {logd("connectToNetwork " + config.getKey());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.getKey());return false;}mCurrentNetworkRemoteHandles.put(ifaceName, pair.first);mCurrentNetworkLocalConfigs.put(ifaceName, pair.second);}SupplicantStaNetworkHal networkHandle =checkSupplicantStaNetworkAndLogFailure(ifaceName, "connectToNetwork");if (networkHandle == null) {loge("No valid remote network handle for network configuration: "+ config.getKey());return false;}PmkCacheStoreData pmkData = mPmkCacheEntries.get(config.networkId);if (pmkData != null&& !WifiConfigurationUtil.isConfigForPskNetwork(config)&& pmkData.expirationTimeInSec > mClock.getElapsedSinceBootMillis() / 1000) {logi("Set PMK cache for config id " + config.networkId);if (networkHandle.setPmkCache(pmkData.data)) {mWifiMetrics.setConnectionPmkCache(true);}}if (!networkHandle.select()) {loge("Failed to select network configuration: " + config.getKey());return false;}return true;}}

它完成两件事情,首先将当前网络配置信息添加到 wpa_supplicant 中,如果当前 supplicant 网络不是该 config 对应的网络则清除当前网络,并在 wpa_supplicant 中选择 config 对应的网络进行连接。

这里 SupplicantStaIfaceHal 自身通过 HashMap<String, WifiConfiguration> 类型对象 mCurrentNetworkLocalConfigs 保存了配置信息,如果发现 isSameNetwork 则进行对应的配置更新操作,否则会网络不同则:

1. 删除掉 mCurrentNetworkRemoteHandles 中保存的对应信息,即底层 HIDL 端的 SupplicantStaNetworkHal 信息;

2. 删除掉 mCurrentNetworkLocalConfigs 中保存的对应信息,实际就是 WifiConfiguration 配置内容;

3. 通过 removeAllNetworks 将所有 ifaceName 对应的 networks 全部删除,实际调用了 listNetworks 取得对应的 network id 列表,并通过 removeNetwork 将其删除;对应的接口以及一个 ifaceName 为何可以对应多个 networks 在后面分析;

4. 通过 addNetworkAndSaveConfig 添加网络以及保存配置,首先其调用 addNetwork 获取到 SupplicantStaNetworkHal 对象 network,紧接着通过 network 的 saveWifiConfiguration 方法设定配置信息;

5. 最终通过 checkSupplicantStaNetworkAndLogFailure 查询确认添加是否成功;

6. 如果添加成功,则进行缓存更新,并且调用 networkHandle 的 select 方法选择对应的网络进行连接,networkHandle 就是 SupplicantStaNetworkHal 类,select 方法其实就是调用到了 HIDL 中对应服务的 select 方法:

    /*** Trigger a connection to this network.** @return true if it succeeds, false otherwise.*/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;}}}

WiFi 连接到网络的过程相关推荐

  1. linux命令行模式连接网络,centos命令行模式连接无线网络的过程

    1. 首先, 你的系统要能驱动无限网卡, 要是人品好的话, 系统已经自带了你的网卡的驱动程序. 不然就要先搞定无线网卡的驱动再说. 不然后面的步骤也就没必要了. 2. 看一下你的无线网卡叫什么: iw ...

  2. 新的计算机的wifi连接无线网络连接,电脑如何连无线网_台式电脑怎么连接wifi步骤-win7之家...

    我们都知道,大多数台式电脑都是通过连接宽带进行上网的,这也是由于台式电脑不方便携带的重要因素之一,然而近日有些用户在没有网线的情况下想要在自己的台式电脑上连接无线网,那么电脑如何连无线网呢?接下来小编 ...

  3. linux命令行模式连接网络,在Linux环境命令行中实现Wifi 连接的方法

    无论何时要安装一款新的 Linux 发行系统,一般的建议都是让您通过有线连接来接到互联网的. 这主要的原因有两条:第一,您的无线网卡也许安装的驱动不正确而不能用:第二,如果您是从命令行中来安装系统的, ...

  4. android wifi连接流程,(九十三) Android O 连接WiFi AP流程梳理续——保存网络-Go语言中文社区...

    前言: 之前在(五十五)Android O 连接WiFi AP流程梳理 梳理连接流程梳理到SupplicantStaNetworkHal 然后没梳理的下去,现在继续梳理下. 之前梳理的时序图 1.流程 ...

  5. ESP32学习入门:WiFi连接网络

    目录 一.ESP32简单介绍 二.ESP32 Wi-Fi模块介绍 三.ESP32 Wi-Fi 编程模型 四.ESP32 Wi-Fi 事件处理流程 五.ESP32 Wi-Fi开发环境 六.ESP32 W ...

  6. Android 9.0 Wifi连接AP过程

    本文分析的是首次连接AP(没有保存参数的AP)的过程. 一.简易流程图 二.代码执行流程 2.1 Settings应用 2.2 WifiManager.java 通过异步通道AsyncChannel来 ...

  7. 计算机连接网络被限制,wifi连接被限制怎么办,教您wifi显示网络受限如何解决

    如今wifi是非常的普及和使用了,只要连接上了,输入密码就可以上网了,但是也相信用户在使用的过程中,会遇到电脑能够连接上家里的无线网络,但提示受限制的情况,这是怎么回事呢?今天,小编就来跟大家分享解决 ...

  8. 详解Wi-Fi连接上网认证接入的原理和过程

    引言 在正式看文章之前,我们需要了解的知识是:WiFi的STA和AP模式指什么? 1.AP,也就是无线接入点,是一个无线网络的创建者,是网络的中心节点.一般家庭或办公室使用的无线路由器就一个AP. 2 ...

  9. 电脑连接不上WiFi无线网,网络显示出现黄星号,或者感叹号最有效的解决方法:

    电脑连接不上WiFi无线网,网络显示出现黄星号,或者感叹号最有效的解决方法: (1)打开360安全卫士. (2)点击功能大全,进入功能区域. (3)点击网络优化,[断网急救箱]. (4)点击全面诊断, ...

  10. 米家扫地机器人重置网络_小米扫地机器人重置wifi怎么链接_米家扫地机器人wifi连接不上怎么办...

    小米扫地机器人是扫地机器人中的中高端品牌,很多人已经购买这款小米扫地机器人,但是在使用过程中链接不上wifi是怎么回事呢?一起来看看小米扫地机器人重置wifi方法吧~ 一.小米扫地机器人重置wifi怎 ...

最新文章

  1. 万字长文带你看尽深度学习中的各种卷积网络
  2. Android启动屏全屏显示
  3. OVS datapath简介(十八)
  4. android 之开关控件的使用
  5. 一个基于Python2.7的智慧校园系统
  6. 使用OLE方式获取数据库架构信息
  7. 生产环境常见的HTTP状态码列表
  8. VIM_shortcut_Cheat_sheet
  9. 基于Flink的高可靠实时ETL系统
  10. Linux环境下Flume的安装
  11. 最新!外国人最常说的100个“中国词”出炉 第一个你绝对想不到…
  12. np.linalg 线性代数
  13. VMware15安装mac10.14
  14. 计算机打不开excel表格,excel表格打不开怎么办?excel表格打不开的原因及解决方法...
  15. 高考476分在浙江计算机学院,2021年高考476分左右能上什么大学(100所)
  16. 「冰狐智能辅助」如何在线实时调试?
  17. 小米10获取root权限_2020年小米红米Miflash新版刷机救砖恢复去除ROOT权限教程
  18. 任意流(随机流)——RandomAccessFile
  19. 手把手教你搭建LAMP环境,运行第一个属于你的个人网站
  20. 绝对正确!解释“超键、候选键和主键”之间的关系

热门文章

  1. python3计算运行时间_性能分析之代码运行时间计算——Python timeit 模块 介绍
  2. Xcode8报错:No code signature found
  3. [Oracle]ORA-600[kdBlkCheckError]LOB坏块处理
  4. Ubuntu 14.04 配置iptables防火墙
  5. Web 网页开发的一点心得
  6. asp.net连接mssql server的方式
  7. Silverlight socket组件
  8. DNS在什么情况下才能动态更新|活动目录集成的dns区域
  9. ExecutorService的shutDown和shutDownNow方法的区别
  10. jsp页面什么时候用 .do 和 .jsp