wifi连接上后是怎么提供网络的?

2024-03-09 20:20

本文主要是介绍wifi连接上后是怎么提供网络的?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

干了六个月的网络协议栈,又回到了wifi老本行,所以我最近又开始研读 Android wifi fwk的源码了
之前还在干wifi的时候就思考过一个问题,wifi区别于蓝牙的一个很明显的点是,wifi可以提供 access to Internet
所以我想看看wifi连接成功后是怎么给上层app提供网络的

前言:研读过程中发现整个机制中有大量的类,且它们的命名非常符合自身的功能,这是我觉得oop语言很有趣也是很容易上手的原因
与之前解决 WNS 选网过程一样,解读的过程中我会尝试给出一个大概的通俗语言描述的模型

注册 NetworkOffer

WifiService(SystemService的子类)在完全开机后,会执行 handleBootCompleted() 方法,注册自己魔改的几个NetworkFactory
我们只关注 WifiNetworkFactory

//WifiServiceImpl.java
public void handleBootCompleted() {mWifiThreadRunner.post(() -> {Log.d(TAG, "Handle boot completed");//...mWifiInjector.getWifiNetworkFactory().register();mWifiInjector.getUntrustedWifiNetworkFactory().register();mWifiInjector.getOemWifiNetworkFactory().register();});
}

NetworkFactory register动作主要做的是

  1. ConnectivityManager.registerNetworkProvider(new NetworkProvider)
  2. handleOfferNetwork -> ConnectivityManager.offerNetwork
//NetworkFactoryImpl.java
private void register(final String logTag, final boolean listenToAllRequests) {mProvider = new NetworkProvider(mContext, NetworkFactoryImpl.this.getLooper(), logTag) {@Overridepublic void onNetworkRequested(@NonNull NetworkRequest request, int score,int servingProviderId) {handleAddRequest(request);}@Overridepublic void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) {handleRemoveRequest(request);}};((ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider);if (listenToAllRequests) {sendMessage(obtainMessage(CMD_LISTEN_TO_ALL_REQUESTS));} else {sendMessage(obtainMessage(CMD_OFFER_NETWORK));}
}//handle CMD_OFFER_NETWORK msg 的逻辑
//此处 mScore == 0
private void handleOfferNetwork(@NonNull final NetworkScore score) {mProvider.registerNetworkOffer(score, mCapabilityFilter, mExecutor, mRequestCallback);
}
//NetworkProvider.java
public void registerNetworkOffer(@NonNull final NetworkScore score,@NonNull final NetworkCapabilities caps, @NonNull final Executor executor,@NonNull final NetworkOfferCallback callback) {mContext.getSystemService(ConnectivityManager.class).offerNetwork(providerId, score, caps, proxy);
}

简单总结:到这里,wifi fwk已经成功地向 CS 注册了一个 NetworkProvider,并且经由这个 NetworkProvider 给出了一个 NetworkOffer
这个 NetworkOffer 就是用来去 satisfy 上层app发起的 NetworkRequest 的,当 CS match 某NetworkOffer 和 某NetworkRequest 的时候,就意味着这个app发起的网络请求将由匹配的网络来处理
不过,wifi fwk给出的这个 NetworkOffer尚处于不能 handle network request 的状态,因为它的 score 是 0

创建NetworkAgent

wifi fwk STA mode的状态机进入 L2ConnectedState 后(L2表示关联上了,之后会进行DHCP,拿到ip后进入L3ConnectedState),会创建 NetworkAgent

//ClientModeImpl.java
//class L2ConnectedState的EA
mNetworkAgent = mWifiInjector.makeWifiNetworkAgent(nc, mLinkProperties, naConfig,mNetworkFactory.getProvider(), new WifiNetworkAgentCallback());
mWifiScoreReport.setNetworkAgent(mNetworkAgent);

如上代码所示,WifiScoreReport 持 WifiNetworkAgent ,它会根据wifi链路状态实时地更新wifi网络在 CS 中的评分(通过调用 sendNetworkScore 方法)

创建 NetworkAgent 触发的一系列动作如下
最主要的是 创建NetworkMonitor

//WifiNetworkAgent.java
public WifiNetworkAgent(@NonNull Context context,@NonNull Looper looper,@NonNull NetworkCapabilities nc,@NonNull LinkProperties lp,@NonNull NetworkAgentConfig config,@Nullable NetworkProvider provider,@NonNull Callback wifiNetworkAgentCallback) {super(context, looper, TAG, nc, lp, ConnectedScore.WIFI_INITIAL_SCORE, config, provider);register();
}//NetworkAgent.java
public Network register() {synchronized (mRegisterLock) {final ConnectivityManager cm = (ConnectivityManager) mInitialConfiguration.context.getSystemService(Context.CONNECTIVITY_SERVICE);mNetwork = cm.registerNetworkAgent(new NetworkAgentBinder(mHandler),new NetworkInfo(mInitialConfiguration.info),mInitialConfiguration.properties, mInitialConfiguration.capabilities,mInitialConfiguration.score, mInitialConfiguration.config, providerId);}return mNetwork;
}//ConnectivityService.java
private Network registerNetworkAgentInternal(INetworkAgent na, NetworkInfo networkInfo,LinkProperties linkProperties, NetworkCapabilities networkCapabilities,NetworkScore currentScore, NetworkAgentConfig networkAgentConfig, int providerId,int uid) {LinkProperties lp = new LinkProperties(linkProperties);final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);final NetworkAgentInfo nai = new NetworkAgentInfo(na,new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),this, mNetd, mDnsResolver, providerId, uid, mLingerDelayMs,mQosCallbackTracker, mDeps);mDeps.getNetworkStack().makeNetworkMonitor(nai.network, name, new NetworkMonitorCallbacks(nai));return nai.network;
}

NetworkMonitor创建成功后,CS 会触发 onNetworkMonitorCreated 回调,处理逻辑是 mNetworkMonitor.start()
我们在 main log中经常可以看到 NetworkMonitor http/https/dns probe fail,这说明 NetworkMonitor 的功能是受控去 probe 指定url,根据返回的status code判断当前链接的状态

实时更新 Network

wifi fwk STA mode处于 L2ConnectedState,接收到 CMD_IP_CONFIGURATION_SUCCESSFUL msg(意味着DHCP完成,这个网络有了自己的ip)

//ClientModeImpl.java
case CMD_IP_CONFIGURATION_SUCCESSFUL: {if (getConnectedWifiConfigurationInternal() == null || mNetworkAgent == null) {mWifiNative.disconnect(mInterfaceName);} else {handleSuccessfulIpConfiguration();sendConnectedState();transitionTo(mL3ConnectedState);}break;
}private void sendConnectedState() {mNetworkAgent.markConnected();sendNetworkChangeBroadcast(DetailedState.CONNECTED);
}//NetworkAgent.java
public void markConnected() {mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null /* reason */,mNetworkInfo.getExtraInfo());queueOrSendNetworkInfo(mNetworkInfo);
}

markConnected 之后,NetworkAgent 会把更新了状态的 NetworkInfo 同步给 CS
同步过程如下

//NetworkAgentInfo.java
public void sendNetworkInfo(@NonNull NetworkInfo info) {mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_INFO_CHANGED,new Pair<>(NetworkAgentInfo.this, info)).sendToTarget();
}//ConnectivityService.java
//NetworkStateTrackerHandler handle this msg
case NetworkAgent.EVENT_NETWORK_INFO_CHANGED: {NetworkInfo info = (NetworkInfo) arg.second;updateNetworkInfo(nai, info);break;
}private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo info) {if (!networkAgent.everConnected && state == NetworkInfo.State.CONNECTED) {rematchAllNetworksAndRequests();} else if (state == NetworkInfo.State.DISCONNECTED) {networkAgent.disconnect();}
}

rematchAllNetworksAndRequests 做的事情便是重新匹配 Network 和 NetworkRequest
我们在main log中经常可以见到 CS NetworkRequest reassign 的打印,这代表原来由某网络负责的NetworkRequest被分配给另一网络处理了
任何一个网络的状态稍有改变都会触发这个动作

WifiScoreReport sendNetworkScore 后触发的流程与上面类似,只不过 msg 换成了 EVENT_NETWORK_SCORE_CHANGED

//ConnectivityService.java
private void updateNetworkScore(@NonNull final NetworkAgentInfo nai, final NetworkScore score) {nai.setScore(score);rematchAllNetworksAndRequests();
}

总结

WifiService 在开机完成后就像 CS 注册了一个 NetworkProvider,并经由这个NetworkProvider注册了一个 NetworkOffer,只不过处于一个无法向外提供服务的状态。
当连接上某wifi(完成了数据链路层的连接)后,wifi 创建一个 NetworkAgent 用于管理这个网络,同时CS创建一个 NetworkMonitor 用于监管这个网络。
当DHCP完成,wifi网络理论上可以与外界通信后,wifi 的NetworkAgent实时地告知 CS 其NetworkInfo 的改动, CS 会重新调整 NetworkRequest 与 Network 的匹配关系。

后续研读计划

这个方面实际要研读的东西还有很多,一开始是想要搞懂wifi连接上后如何提供网络的

看和写的过程中意识到还应该系统地弄清楚这些问题

  • wifi 改动网络评分的细节(WifiNetworkAgent + WifiScoreReport)
  • CS rematch 的细节(显然CS绝对不是唯评分论的单一匹配机制)
  • macth后一个NetworkRequest是怎么被satisfy的 (数据通路是怎样的)

后记:理解了这个模型,大概可以搞清wifi连接上后是怎么提供网络的了,但是搞清楚这个对于日常工作做trouble shooting有什么帮助吗?
貌似也没有多大帮助
哈哈哈哈,图一乐

这篇关于wifi连接上后是怎么提供网络的?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/791844

相关文章

电脑死机无反应怎么强制重启? 一文读懂方法及注意事项

《电脑死机无反应怎么强制重启?一文读懂方法及注意事项》在日常使用电脑的过程中,我们难免会遇到电脑无法正常启动的情况,本文将详细介绍几种常见的电脑强制开机方法,并探讨在强制开机后应注意的事项,以及如何... 在日常生活和工作中,我们经常会遇到电脑突然无反应的情况,这时候强制重启就成了解决问题的“救命稻草”。那

MySQL中的交叉连接、自然连接和内连接查询详解

《MySQL中的交叉连接、自然连接和内连接查询详解》:本文主要介绍MySQL中的交叉连接、自然连接和内连接查询,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、引入二、交php叉连接(cross join)三、自然连接(naturalandroid join)四

python连接本地SQL server详细图文教程

《python连接本地SQLserver详细图文教程》在数据分析领域,经常需要从数据库中获取数据进行分析和处理,下面:本文主要介绍python连接本地SQLserver的相关资料,文中通过代码... 目录一.设置本地账号1.新建用户2.开启双重验证3,开启TCP/IP本地服务二js.python连接实例1.

Ubuntu中远程连接Mysql数据库的详细图文教程

《Ubuntu中远程连接Mysql数据库的详细图文教程》Ubuntu是一个以桌面应用为主的Linux发行版操作系统,这篇文章主要为大家详细介绍了Ubuntu中远程连接Mysql数据库的详细图文教程,有... 目录1、版本2、检查有没有mysql2.1 查询是否安装了Mysql包2.2 查看Mysql版本2.

Python3.6连接MySQL的详细步骤

《Python3.6连接MySQL的详细步骤》在现代Web开发和数据处理中,Python与数据库的交互是必不可少的一部分,MySQL作为最流行的开源关系型数据库管理系统之一,与Python的结合可以实... 目录环境准备安装python 3.6安装mysql安装pymysql库连接到MySQL建立连接执行S

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

SpringBoot使用OkHttp完成高效网络请求详解

《SpringBoot使用OkHttp完成高效网络请求详解》OkHttp是一个高效的HTTP客户端,支持同步和异步请求,且具备自动处理cookie、缓存和连接池等高级功能,下面我们来看看SpringB... 目录一、OkHttp 简介二、在 Spring Boot 中集成 OkHttp三、封装 OkHttp

Spring Boot 整合 MyBatis 连接数据库及常见问题

《SpringBoot整合MyBatis连接数据库及常见问题》MyBatis是一个优秀的持久层框架,支持定制化SQL、存储过程以及高级映射,下面详细介绍如何在SpringBoot项目中整合My... 目录一、基本配置1. 添加依赖2. 配置数据库连接二、项目结构三、核心组件实现(示例)1. 实体类2. Ma

电脑win32spl.dll文件丢失咋办? win32spl.dll丢失无法连接打印机修复技巧

《电脑win32spl.dll文件丢失咋办?win32spl.dll丢失无法连接打印机修复技巧》电脑突然提示win32spl.dll文件丢失,打印机死活连不上,今天就来给大家详细讲解一下这个问题的解... 不知道大家在使用电脑的时候是否遇到过关于win32spl.dll文件丢失的问题,win32spl.dl