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) {
        @Override
        public void onNetworkRequested(@NonNull NetworkRequest request, int score,
                int servingProviderId) {
            handleAddRequest(request);
        }

        @Override
        public 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有什么帮助吗?
貌似也没有多大帮助
哈哈哈哈,图一乐

  • 24
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 首先,你需要一个可以连接到micro:bit板的wifi路由器,然后使用micro:bit板上的USB-A to Micro-B数据线将microbit板与路由器连接起来,最后使用micro:bit板上的微处理器来连接wifi网络。 ### 回答2: 要连接micro:bit板的wifi,首先需要确保你的micro:bit板已经连接到了电脑或者其他设备上。接下来按照以下步骤进行: 1. 打开micro:bit的编程界面,可以选择使用MakeCode或Python编程环境。 2. 在代码编辑器中,找到“无线电”模块,点击“无线电”模块下面的“wifi”模块。 3. 在“wifi”模块中,点击“连接到Wi-Fi”。 4. 输入你要连接的Wi-Fi网络的名称(也叫SSID)和密码。这些信息通常可以在你的Wi-Fi路由器上找到。 5. 点击“连接”按钮,等待几秒钟,直到板子成功连接到Wi-Fi网络。 6. 连接成功后,你可以使用“无线电”模块中的其他功能来发送和接收数据。 需要注意的是,micro:bit只支持2.4GHz的Wi-Fi网络,不支持5GHz的网络。此外,由于micro:bit的处理能力有限,连接大量设备或需要高速数据传输的应用可能会导致性能下降。 连接Wi-Fi网络后,你可以编写相关代码,利用Wi-Fi传输数据、远程控制等功能。例如,你可以编写代码来控制micro:bit板上的LED灯,通过Wi-Fi网络接收命令,并执行相应的操作。 总之,连接micro:bit板的Wi-Fi并不复杂,只需在编程环境中选择相应模块,输入Wi-Fi网络的名称和密码,点击连接即可。 ### 回答3: 要通过WiFi连接micro:bit板,首先需要确保micro:bit板上有WiFi模块。如果没有,可以通过购买WiFi扩展板来进行连接。以下是连接步骤: 1. 在micro:bit板上插入WiFi模块。有些模块会需要安装驱动程序,可以根据说明书进行安装。 2. 在电脑上打开一个WiFi管理工具,搜索附近的WiFi网络。找到要连接网络,并记住网络名称(SSID)和密码。 3. 在micro:bit板上使用编程软件(如MakeCode或MicroPython)编写一个程序,用于连接WiFi网络。 4. 在程序中,使用适当的命令来初始化WiFi模块,并指定要连接网络名称和密码。例如,在MakeCode中,可以使用"WiFi.connect"命令。 5. 将程序下载到micro:bit板上,并通过USB连接电脑。 6. 等待片刻,让micro:bit板连接WiFi网络连接成功后,可以使用其他命令和功能来访问互联网或进行其他与网络相关的操作。 需要注意的是,不同的WiFi模块和编程软件可能会有些差异,具体的操作步骤可能会有所不同。因此,在实际操作中,请参考所使用的硬件和软件的说明文档,并根据需要进行适当的调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值