Android 9.0 网络评分之--NetworkAgent

晋鹤轩
2023-12-01

一、NetworkAgent 和NetworkFactory的区别

NetworkAgent是被NetworkFactory创建的,这里的创建并不是说在NetworkFactory内部创建
NetworkAgent,而是说,在NetworkFactory这个环境就绪之后,网络提供者才可以创建
NetworkAgent。并且在一个NetworkFactory中可以创建不同的NetworkAgent,
他们拥有不同的Capabilities等参数。
而他们之间还有一个区别就是,NetworkFactory是在系统初始化时就被创建,
而NetworkAgent是在真正接入网络时才会创建。
我们用运营商之间的关系来比喻他们的关系。
NetworkFactory相当于不同的运营商,比如中国电信、铁通、移动,他们具备联通互联网的能
力,当用户入网时就决定了自己的运营商(即完成NetworkFactory初始化)。
但同时在每个运营商内部又创建各个不同的接入点,比如对于中国电信来说,
还分为上海电信、河北电信等,只有当用户打开电脑真正上网的时候,
才会被分配具体的接入点(即完成NetworkAgent初始化)。
也就是说,同一个NetworkFactory可以在不同的时刻根据需要创建不同的NetworkAgent,
比如使用数据上网时,会根据当前的需要(发送MMS还是IMS,或者单纯上网)
来创建不同参数的NetworkAgent(不同的APN参数)对象,然后将其注册到ConnectivityService中。

二、NetworkAgent的初始化过程。

在NetworkAgent 的构造函数中会调用ConnectivityService的registerNetworkAgent方法注册。
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
super(looper);
LOG_TAG = logTag;
mContext = context;
if (ni == null || nc == null || lp == null) {
throw new IllegalArgumentException();
}

    if (VDBG) log("Registering NetworkAgent");
    ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
            Context.CONNECTIVITY_SERVICE);
    netId = cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni),
            new LinkProperties(lp), new NetworkCapabilities(nc), score, misc);
}

但是NetworkAgent 方法是在哪里实例化的呢 ? 是在 EthrernetNetworkFactory里面,具体流程我们接着分析。在framework下全局代码搜索的时候可以看到NetworkAgent 是在EthernetNetworkFactory 里面实例化的。
代码路径:frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetNetworkFactory.java
void onIpLayerStarted(LinkProperties linkProperties) {
if (mNetworkAgent != null) {
Log.e(TAG, “Already have a NetworkAgent - aborting new request”);
// wtf: why stop current agent??
//stop();
return;
}
mLinkProperties = linkProperties;
mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddress);
mNetworkInfo.setIsAvailable(true);
// set specifier caps for automotive multiple ETH devices such as meter tbox and generic eth.
mCapabilities.setNetworkSpecifier(new StringNetworkSpecifier(mLinkProperties.getInterfaceName()));

        // Create our NetworkAgent.
        mNetworkAgent = new NetworkAgent(mHandler.getLooper(), mContext,
                NETWORK_TYPE, mNetworkInfo, mCapabilities, mLinkProperties,
                NETWORK_SCORE) {
            public void unwanted() {
                if (this == mNetworkAgent) {
					// wtf: why stop current agent??
                    //stop();
                } else if (mNetworkAgent != null) {
                    Log.d(TAG, "Ignoring unwanted as we have a more modern " +
                            "instance");
                }  // Otherwise, we've already called stop.
            }
        };
    }

onIpLayerStarted 是IpClient 中的一个callback 回调中调用
private final IpClient.Callback mIpClientCallback = new IpClient.Callback() {
@Override
public void onProvisioningSuccess(LinkProperties newLp) {
mHandler.post(() -> onIpLayerStarted(newLp));
}

        @Override
        public void onProvisioningFailure(LinkProperties newLp) {
            mHandler.post(() -> onIpLayerStopped(newLp));
        }

        @Override
        public void onLinkPropertiesChange(LinkProperties newLp) {
            mHandler.post(() -> updateLinkProperties(newLp));
        }
    };

二、什么是IpClient
Google官网链接:https://source.android.google.cn/devices/architecture/modular-system/networking

IP 服务。 IpClient(以前称为 IpManager)组件负责处理 IP 层配置和维护。在 Android 9 中,它被蓝牙等组件用于进程间处理,被 WLAN 等组件用于进程内处理。DhcpClient 组件从 DHCP 服务器获取 IP 地址,以便将它们分配给接口。
IpClient:
EtherNetworkFactory 中有一个内部类NetworkInterfaceState,这个内部类主要记录链路状态和属性。
其中就有ipclient。ipclient 涉及ip的DHCP请求与分配,他的本质是一个状态机。

private static class NetworkInterfaceState {
    final String name;

    private final String mHwAddress;
    private final NetworkCapabilities mCapabilities;
    private final Handler mHandler;
    private final Context mContext;
    private final NetworkInfo mNetworkInfo;

    private static String sTcpBufferSizes = null;  // Lazy initialized.

    private boolean mLinkUp;
    private LinkProperties mLinkProperties = new LinkProperties();

    private IpClient mIpClient;
    private NetworkAgent mNetworkAgent;
    private IpConfiguration mIpConfig;

但IpClient 底层是怎么一步步调用上来的呢,这个要去跟一下代码一步步看了。

三、IpClient的初始化过程

3.1、EthernetTracker 中监听到有新的网络接口被添加了,会调用 maybeTrackInterface
EthernetTracker 是一个监听网络接口状态变化的类,他通过观察者模式和NetworkManagementService连系起来,而NetworkManagementService最终又是与NetD关联的,NetD是与kernel关联的,有兴趣的可以往下一步步跟一下代码,这篇文章不贴出来了。

代码路径:frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetTracker.java
@Override
public void interfaceAdded(String iface) {
if (DBG) {
Log.i(TAG, "szh,interfaceAdded, iface: " + iface);
}
mHandler.post(() -> maybeTrackInterface(iface));
}

3.2、maybeTrackInterface 方法会调用updateIpConfiguration更新网络接口的IP配置信息,同时添加网口。

private void maybeTrackInterface(String iface) {
    if (DBG) Log.i(TAG, "maybeTrackInterface " + iface);
    // If we don't already track this interface, and if this interface matches
    // our regex, start tracking it.
    if (!iface.matches(mIfaceMatch) || mFactory.hasInterface(iface)) {
        return;
    }

    if (mIpConfigForDefaultInterface != null) {
        updateIpConfiguration(iface, mIpConfigForDefaultInterface);
        mIpConfigForDefaultInterface = null;
    }

    addInterface(iface);
}

3.3、调用NetworkFactory的updateIpConfiguration方法去更新updateIpConfiguration
这里面EthernetTracker 的updateIpConfiguration 将IP配置信息放到 mIpConfigurations 中最终调用的是 EthernetNetworkFactory 的updateIpConfiguration。
void updateIpConfiguration(String iface, IpConfiguration ipConfiguration) {
if (DBG) {
Log.i(TAG, "updateIpConfiguration, iface: " + iface + ", cfg: " + ipConfiguration);
}

    mConfigStore.write(iface, ipConfiguration);
    mIpConfigurations.put(iface, ipConfiguration);

    mHandler.post(() -> mFactory.updateIpConfiguration(iface, ipConfiguration));
}

EthernetNetworkFactory 中调用updateIPConfiguration,然后设置ip配置信息
void updateIpConfiguration(String iface, IpConfiguration ipConfiguration) {
NetworkInterfaceState network = mTrackingInterfaces.get(iface);
if (network != null) {
network.setIpConfig(ipConfiguration);
}
}

继续:
void setIpConfig(IpConfiguration ipConfig) {
this.mIpConfig = ipConfig;
stop();
start();
}

3.4、然后看start方法里面初始化里IPClient这个对象。

    private void start() {
        if (mIpClient != null) {
            if (DBG) Log.d(TAG, "IpClient already started");
            return;
        }
        if (DBG) {
            Log.d(TAG, String.format("starting IpClient(%s): mNetworkInfo=%s", name,
                    mNetworkInfo));
        }

        mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddress);

        mIpClient = new IpClient(mContext, name, mIpClientCallback);

        if (sTcpBufferSizes == null) {
            sTcpBufferSizes = mContext.getResources().getString(
                    com.android.internal.R.string.config_ethernet_tcp_buffers);
        }
        provisionIpClient(mIpClient, mIpConfig, sTcpBufferSizes);
    }

四、NetworkAgent与ConnectivityService的连接过程

ConnectivityManager.registerNetworkAgent–>ConnectivityService.registerNetworkAgent
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
super(looper);
LOG_TAG = logTag;
mContext = context;
if (ni == null || nc == null || lp == null) {
throw new IllegalArgumentException();
}

    if (VDBG) log("Registering NetworkAgent");
    ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
            Context.CONNECTIVITY_SERVICE);
    netId = cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni),
            new LinkProperties(lp), new NetworkCapabilities(nc), score, misc);
}

在ConnectivityService registerNetworkAgent中有新的NetworkAgent 注册之后会更新LinkProperties
public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
int currentScore, NetworkMisc networkMisc) {
enforceConnectivityInternalPermission();

    LinkProperties lp = new LinkProperties(linkProperties);
    lp.ensureDirectlyConnectedRoutes();
    // TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network
    // satisfies mDefaultRequest.
    final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
    final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
            new Network(reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore,
            mContext, mTrackerHandler, new NetworkMisc(networkMisc), mDefaultRequest, this);
    // Make sure the network capabilities reflect what the agent info says.
    nai.networkCapabilities = mixInCapabilities(nai, nc);
    synchronized (this) {
        nai.networkMonitor.systemReady = mSystemReady;
    }
    final String extraInfo = networkInfo.getExtraInfo();
    final String name = TextUtils.isEmpty(extraInfo)
            ? nai.networkCapabilities.getSSID() : extraInfo;
    addValidationLogs(nai.networkMonitor.getValidationLogs(), nai.network, name);
    if (DBG) log("registerNetworkAgent " + nai);
    mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
    return nai.network.netId;
}

发送EVENT_REGISTER_NETWORK_AGENT 去更新updateNetworkInfo 这些网络状态,并且连接NetworkAgent的 AsyncChannel
private void handleRegisterNetworkAgent(NetworkAgentInfo nai) {
if (VDBG) log(“Got NetworkAgent Messenger”);
mNetworkAgentInfos.put(nai.messenger, nai);
synchronized (mNetworkForNetId) {
mNetworkForNetId.put(nai.network.netId, nai);
}
nai.asyncChannel.connect(mContext, mTrackerHandler, nai.messenger);
NetworkInfo networkInfo = nai.networkInfo;
nai.networkInfo = null;
updateNetworkInfo(nai, networkInfo);
updateUids(nai, null, nai.networkCapabilities);
}

这里连接上了,然后建立双向连接
} else if (mNetworkAgentInfos.containsKey(msg.replyTo)) {
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
if (VDBG) log(“NetworkAgent connected”);
// A network agent has requested a connection. Establish the connection.
mNetworkAgentInfos.get(msg.replyTo).asyncChannel.

参考博客链接 :https://blog.csdn.net/u010961631/article/details/48971651

 类似资料: