Android WiFi Dhcp 获取到 IP 和配置的过程

20 篇文章 5 订阅
9 篇文章 1 订阅

在 ConnectivityService 中负责配置,由 updateLinkProperties 来完成:

    private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties newLp,
            LinkProperties oldLp) {
        int netId = networkAgent.network.netId;

        // The NetworkAgent does not know whether clatd is running on its network or not, or whether
        // a NAT64 prefix was discovered by the DNS resolver. Before we do anything else, make sure
        // the LinkProperties for the network are accurate.
        networkAgent.clatd.fixupLinkProperties(oldLp, newLp);

        updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities,
                networkAgent.networkInfo.getType());

        // update filtering rules, need to happen after the interface update so netd knows about the
        // new interface (the interface name -> index map becomes initialized)
        updateVpnFiltering(newLp, oldLp, networkAgent);

        updateMtu(newLp, oldLp);
        // TODO - figure out what to do for clat
//        for (LinkProperties lp : newLp.getStackedLinks()) {
//            updateMtu(lp, null);
//        }
        if (isDefaultNetwork(networkAgent)) {
            updateTcpBufferSizes(newLp.getTcpBufferSizes());
        }

        updateRoutes(newLp, oldLp, netId);
        updateDnses(newLp, oldLp, netId);
        // Make sure LinkProperties represents the latest private DNS status.
        // This does not need to be done before updateDnses because the
        // LinkProperties are not the source of the private DNS configuration.
        // updateDnses will fetch the private DNS configuration from DnsManager.
        mDnsManager.updatePrivateDnsStatus(netId, newLp);

        if (isDefaultNetwork(networkAgent)) {
            handleApplyDefaultProxy(newLp.getHttpProxy());
        } else {
            updateProxy(newLp, oldLp);
        }

        updateWakeOnLan(newLp);

        // Captive portal data is obtained from NetworkMonitor and stored in NetworkAgentInfo,
        // it is not contained in LinkProperties sent from NetworkAgents so needs to be merged here.
        newLp.setCaptivePortalData(networkAgent.captivePortalData);

        // TODO - move this check to cover the whole function
        if (!Objects.equals(newLp, oldLp)) {
            synchronized (networkAgent) {
                networkAgent.linkProperties = newLp;
            }
            // Start or stop DNS64 detection and 464xlat according to network state.
            networkAgent.clatd.update();
            notifyIfacesChangedForNetworkStats();
            networkAgent.networkMonitor().notifyLinkPropertiesChanged(
                    new LinkProperties(newLp, true /* parcelSensitiveFields */));
            if (networkAgent.everConnected) {
                notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
            }
        }

        mKeepaliveTracker.handleCheckKeepalivesStillValid(networkAgent);
    }

上述函数里面调用了各种 updateXXX 操作实现了更新过程,其实际调用者为 handleUpdateLinkProperties:

    public void handleUpdateLinkProperties(NetworkAgentInfo nai, LinkProperties newLp) {
        ensureRunningOnConnectivityServiceThread();

        if (getNetworkAgentInfoForNetId(nai.network.netId) != nai) {
            // Ignore updates for disconnected networks
            return;
        }
        if (VDBG || DDBG) {
            log("Update of LinkProperties for " + nai.toShortString()
                    + "; created=" + nai.created
                    + "; everConnected=" + nai.everConnected);
        }
        // TODO: eliminate this defensive copy after confirming that updateLinkProperties does not
        // modify its oldLp parameter.
        updateLinkProperties(nai, newLp, new LinkProperties(nai.linkProperties));
    }

处理过程在 内部类 NetworkStateTrackerHandler 的 maybeHandleNetworkAgentMessage 接口中,它被 NetworkStateTrackerHandler 的 handleMessage 调用处理可能的一些消息:

        public void handleMessage(Message msg) {
            if (!maybeHandleAsyncChannelMessage(msg)
                    && !maybeHandleNetworkMonitorMessage(msg)
                    && !maybeHandleNetworkAgentInfoMessage(msg)) {
                maybeHandleNetworkAgentMessage(msg);
            }
        }

而 NetworkStateTrackerHandler 作为内部类,继承了 Handler 类,其在 ConnectivityService 类中的对象 mTrackerHandler 在类构造过程中创建,其使用有两个方面:

①:在 handleRegisterNetworkProvider 过程中作为 SrcHandler 来处理 AsyncChannel 的消息,用于与 NetworkProvider 通信的消息处理。而 handleRegisterNetworkProvider 其调用则在 registerNetworkProvider 中进行 EVENT_REGISTER_NETWORK_PROVIDER 消息发送之后,在内部类 InternalHandler 的 handleMessage 处理过程中调用处理。

WiFi 对应的 NetworkProvider 的注册

在 WifiServiceImpl 的 handleBootCompleted 处理过程中调用了 ClientModeImpl 的 handleBootCompleted 接口,在其中执行了 sendMessage 操作将 CMD_BOOT_COMPLETED 发给自己,而其处理在 DefaultState 中:

                case CMD_BOOT_COMPLETED:
                    // get other services that we need to manage
                    getAdditionalWifiServiceInterfaces();
                    registerNetworkFactory();
                    mSarManager.handleBootCompleted();
                    break;

这里面执行了 registerNetworkFactory:

    void registerNetworkFactory() {
        if (!checkAndSetConnectivityInstance()) return;
        mNetworkFactory.register();
        mUntrustedNetworkFactory.register();
    }

而 mNetworkFactory 为 WifiNetworkFactory 类对象,继承了 NetworkFactory 类,其 register 接口如下:

    /* Registers this NetworkFactory with the system. May only be called once per factory. */
    public void register() {
        if (mProvider != null) {
            throw new IllegalStateException("A NetworkFactory must only be registered once");
        }
        if (DBG) log("Registering NetworkFactory");

        mProvider = new NetworkProvider(mContext, NetworkFactory.this.getLooper(), LOG_TAG) {
            @Override
            public void onNetworkRequested(@NonNull NetworkRequest request, int score,
                    int servingProviderId) {
                handleAddRequest(request, score, servingProviderId);
            }

            @Override
            public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) {
                handleRemoveRequest(request);
            }
        };

        ((ConnectivityManager) mContext.getSystemService(
            Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider);
    }

这里创建了 NetworkProvider 对象 mProvider 主要实现了网络请求的调用接口,然后通过 CONNECTIVITY_SERVICE 的 client 应用(ConnectivityManager)调用服务接口 registerNetworkProvider 将其注册到 ConnectivityService 中。

② 在 handleRegisterNetworkAgent 过程中作为 SrcHandler 来处理 AsyncChannel 的消息,用于与 NetworkAgent 通信的消息处理。

那么什么时候调用 registerNetworkAgent 呢?

可以看到直接的调用就是在 ConnectivityManager 中,它作为 ConnectivityService 的客户端类进行服务调用,实际动作发生在 NetworkAgent 类中的 register 接口中:

    /**
     * Register this network agent with ConnectivityService.
     *
     * This method can only be called once per network agent.
     *
     * @return the Network associated with this network agent (which can also be obtained later
     *         by calling getNetwork() on this agent).
     * @throws IllegalStateException thrown by the system server if this network agent is
     *         already registered.
     */
    @NonNull
    public Network register() {
        if (VDBG) log("Registering NetworkAgent");
        synchronized (mRegisterLock) {
            if (mNetwork != null) {
                throw new IllegalStateException("Agent already registered");
            }
            final ConnectivityManager cm = (ConnectivityManager) mInitialConfiguration.context
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            mNetwork = cm.registerNetworkAgent(new Messenger(mHandler),
                    new NetworkInfo(mInitialConfiguration.info),
                    mInitialConfiguration.properties, mInitialConfiguration.capabilities,
                    mInitialConfiguration.score, mInitialConfiguration.config, providerId);
            mInitialConfiguration = null; // All this memory can now be GC'd
        }
        return mNetwork;
    }

在 ClientModeImpl 中内部类 WifiNetworkAgent 继承了 NetworkAgent 类,register 接口的调用发生在 WiFiNetworkAgent 的构造过程中:

        WifiNetworkAgent(Context c, Looper l, String tag, NetworkCapabilities nc, LinkProperties lp,
                int score, NetworkAgentConfig config, NetworkProvider provider) {
            super(c, l, tag, nc, lp, score, config, provider);
            register();
        }

而 WiFiNetworkAgent 的创建发生在 ClientModeImpl 内部类 L2ConnectedState 的 enter 过程中,在 WiFi 连接建立进入 L2ConnectedState 时建立了 L2 网络连接,开始进行创建 NetworkAgent 用于维护连接状态。

因而此时我们回到开始的讨论,因此对应的消息 EVENT_NETWORK_PROPERTIES_CHANGED 就是在 ClientModeImpl 发出的:

    private void updateLinkProperties(LinkProperties newLp) {
        if (mVerboseLoggingEnabled) {
            log("Link configuration changed for netId: " + mLastNetworkId
                    + " old: " + mLinkProperties + " new: " + newLp);
        }
        // We own this instance of LinkProperties because IpClient passes us a copy.
        mLinkProperties = newLp;
        if (mNetworkAgent != null) {
            mNetworkAgent.sendLinkProperties(mLinkProperties);
        }

        if (mNetworkAgentState == DetailedState.CONNECTED) {
            // If anything has changed and we're already connected, send out a notification.
            // TODO: Update all callers to use NetworkCallbacks and delete this.
            sendLinkConfigurationChangedBroadcast();
        }

        if (mVerboseLoggingEnabled) {
            StringBuilder sb = new StringBuilder();
            sb.append("updateLinkProperties nid: " + mLastNetworkId);
            sb.append(" state: " + mNetworkAgentState);

            if (mLinkProperties != null) {
                sb.append(" ");
                sb.append(getLinkPropertiesSummary(mLinkProperties));
            }
            logd(sb.toString());
        }
    }

这里调用了 NetworkAgent 类对象 mNetworkAgent 的 sendLinkProperties 进行操作:

    private void queueOrSendMessage(int what, Object obj) {
        queueOrSendMessage(what, 0, 0, obj);
    }

    private void queueOrSendMessage(int what, int arg1, int arg2) {
        queueOrSendMessage(what, arg1, arg2, null);
    }

    private void queueOrSendMessage(int what, int arg1, int arg2, Object obj) {
        Message msg = Message.obtain();
        msg.what = what;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        msg.obj = obj;
        queueOrSendMessage(msg);
    }

    private void queueOrSendMessage(Message msg) {
        synchronized (mPreConnectedQueue) {
            if (mAsyncChannel != null) {
                mAsyncChannel.sendMessage(msg);
            } else {
                mPreConnectedQueue.add(msg);
            }
        }
    }

    /**
     * Must be called by the agent when the network's {@link LinkProperties} change.
     * @param linkProperties the new LinkProperties.
     */
    public final void sendLinkProperties(@NonNull LinkProperties linkProperties) {
        Objects.requireNonNull(linkProperties);
        queueOrSendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, new LinkProperties(linkProperties));
    }

如上最终是调用了 mAsyncChannel 的 sendMessage 将消息发送给另一端。这里 AsyncChannel 是在 NetworkAgentHandler 中创建,其在 NetworkAgent 初始化的时候创建,在 register 中作为参数创建了 Messenger 对象,向 CONNECTIVITY_SERVICE 注册网络代理 registerNetworkAgent。

再看 ClientModeImpl 中的 updateLinkProperties 接口调用,发生在 DefaultState 中处理 CMD_UPDATE_LINKPROPERTIES 消息过程中,该消息在内部类 IpClientCallbacksImpl 中的回调中发出,实际上有两个回调接口:

  • onProvisioningSuccess:
  • onLinkPropertiesChange:在 IpClient 中 dispatchCallback 调用了 mCallback 的 onLinkPropertiesChange 接口,在 IpClient 创建过程中通过 callback 参数进行封装获得,而在 ClientModeImpl 的 ConnectModeState 的 enter 过程中调用了 setupClientMode 接口在其中创建了 IpClientCallbacksImpl 对象,它继承了 IpClientCallbacks 类,并将其通过 mFacade.makeIpClient 调用,从而调用了 IpClientUtil.makeIpClient 接口,进而调用到 NetworkStackClient 类的 makeIpClient 接口创建了对应的 IpClient 对象;

 在 IpClient 中 dispatchCallback 接口调用的地方主要为 RunningState 中的 processMessage 过程,在如下情境下会进行 DhcpClient.CMD_POST_DHCP_ACTION 消息的处理:

  •  initial address acquisition succeeds,
  •  renew succeeds or is NAK'd,
  •  rebind succeeds or is NAK'd, or
  •  the lease expires, or
  •  the IPv6-only preferred option is enabled and entering Ipv6OnlyWaitState.

而其中调用了 IpClient 的 handleIPv4Success 接口,里面调用了 dispatchCallback 方法;

另外这里也会处理 DhcpClient.CMD_CONFIGURE_LINKADDRESS 消息,调用 dispatchCallback 接口,不过处理的消息是 PROV_CHANGE_LOST_PROVISIONING;

回过头来看 DhcpClient.CMD_POST_DHCP_ACTION 消息,在 DhcpClient 的 notifySuccess 中会调用其  mController 对象也就是 IpClient 状态机的 sendMessage 接口发送该消息,它的调用者为 ConfiguringInterfaceState 的 enter 接口或者是 DhcpReacquiringState 的 receivePacket 接口,都表示获取到了对应的地址信息。 

 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值