Android 11 Ethernet以太网架构分析(1)——初始化

这篇具有很好参考价值的文章主要介绍了Android 11 Ethernet以太网架构分析(1)——初始化。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

概要

android中以太网常被用作共享网络,或者是定制化设备连接网线的需求。
本章将会详细分析该模块对以太网的逻辑实现,是大家对此有更深入认识。

整体架构流程

初始化

Systemserver

在安卓系统中有一个关于以太网的服务,在systemserver中启动
frameworks/base/services/java/com/android/server/SystemServer.java

            if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET) ||
                    mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
                t.traceBegin("StartEthernet");
                mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
                t.traceEnd();
            }
EthernetService

这个EthernetService类的内容很少,重点主要看他这里初始化了EthernetServiceImpl这个类然后调用其start方法
frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetService.java

public final class EthernetService extends SystemService {

    private static final String TAG = "EthernetService";
    final EthernetServiceImpl mImpl;

    public EthernetService(Context context) {
        super(context);
        mImpl = new EthernetServiceImpl(context);
    }

    @Override
    public void onStart() {
        Log.i(TAG, "Registering service " + Context.ETHERNET_SERVICE);
        publishBinderService(Context.ETHERNET_SERVICE, mImpl);
    }

    @Override
    public void onBootPhase(int phase) {
        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
            mImpl.start();
        }
    }
}
EthernetServiceImpl

frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetServiceImpl.java

public class EthernetServiceImpl extends IEthernetManager.Stub {

首先可以看出他继承了IEthernetManager接口,应该是系统api的服务实现类

继续看他的start方法
创建了一个handler但也只是作为入参传入到EthernetTracker构造中,之后在启动EthernetTracker这个类
猜测EthernetTracker还有更重要的地方,继续追踪其启动

    public void start() {
        Log.i(TAG, "Starting Ethernet service");

        HandlerThread handlerThread = new HandlerThread("EthernetServiceThread");
        handlerThread.start();
        mHandler = new Handler(handlerThread.getLooper());

        mTracker = new EthernetTracker(mContext, mHandler);
        mTracker.start();

        mStarted.set(true);
    }
EthernetTracker

frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetTracker.java
构造方法

    EthernetTracker(Context context, Handler handler) {
        mContext = context;
        mHandler = handler;

        // The services we use.
        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); //获取了网络管理的服务,这个服务是直接和netd进行交互的
        mNMService = INetworkManagementService.Stub.asInterface(b);

        // Interface match regex.
        updateIfaceMatchRegexp(); //更新以太网卡筛选规则,通常是‘eth\\d’

        // Read default Ethernet interface configuration from resources
        final String[] interfaceConfigs = context.getResources().getStringArray(
                com.android.internal.R.array.config_ethernet_interfaces);
        for (String strConfig : interfaceConfigs) {
            parseEthernetConfig(strConfig);//从资源文件中获取并解析默认的以太网络配置 (1)
        }

        mConfigStore = new EthernetConfigStore();//初始化网络配置类

        NetworkCapabilities nc = createNetworkCapabilities(true /* clear default capabilities */);//(2)
        mFactory = new EthernetNetworkFactory(handler, context, nc);
        mFactory.register();//(3)重点是这个mFactory,我们后续讲道,知道是在这里初始化的
    }

parseEthernetConfig的这个解析系统的xml文件,然后读到该类的对象数组中,具体格式如下

    <string-array translatable="false" name="config_ethernet_interfaces">
        
        <item>eth1;12,13,14,15;ip=192.168.0.10/24 gateway=192.168.0.1 dns=4.4.4.4,8.8.8.8</item>
        <item>eth2;;ip=192.168.0.11/24</item>
        <item>eth3;12,13,14,15;ip=192.168.0.12/24;1</item>
       
    </string-array>

createNetworkCapabilities是分析网络功能的静态列表作用,传入参数true代表清除缓存
该方法作用主要是指定当前网络的一个能力和一些相关参数的初始化

start方法

    void start() {
        mConfigStore.read();

        // Default interface is just the first one we want to track.
        mIpConfigForDefaultInterface = mConfigStore.getIpConfigurationForDefaultInterface();
        final ArrayMap<String, IpConfiguration> configs = mConfigStore.getIpConfigurations();
        for (int i = 0; i < configs.size(); i++) {
            mIpConfigurations.put(configs.keyAt(i), configs.valueAt(i));
        }

        try {
            mNMService.registerObserver(new InterfaceObserver());
        } catch (RemoteException e) {
            Log.e(TAG, "Could not register InterfaceObserver " + e);
        }

        mHandler.post(this::trackAvailableInterfaces);
    }

mConfigStore会去读/misc/ethernet/ipconfig.txt这个下面的网络配置,如果用户没有指定,那这块就为空
registerObserver(new InterfaceObserver())主要是监听down up remove add这几个状态然后做对应的处理

    private class InterfaceObserver extends BaseNetworkObserver {

        @Override
        public void interfaceLinkStateChanged(String iface, boolean up) {
            if (DBG) {
                Log.i(TAG, "interfaceLinkStateChanged, iface: " + iface + ", up: " + up);
            }
            mHandler.post(() -> updateInterfaceState(iface, up));
        }

        @Override
        public void interfaceAdded(String iface) {
            mHandler.post(() -> maybeTrackInterface(iface));
        }

        @Override
        public void interfaceRemoved(String iface) {
            mHandler.post(() -> stopTrackingInterface(iface));
        }
    }

最后执行trackAvailableInterfaces这个方法

    private void trackAvailableInterfaces() {
        try {
            final String[] ifaces = mNMService.listInterfaces(); //遍历当前网卡接口,返回字符数组
            for (String iface : ifaces) {
                maybeTrackInterface(iface);//挨个做处理
            }
        } catch (RemoteException | IllegalStateException e) {
            Log.e(TAG, "Could not get list of interfaces " + e);
        }
    }

继续看maybeTrackInterface这个方法

    private void maybeTrackInterface(String iface) {
        if (!iface.matches(mIfaceMatch)) { //如果与设定的网卡名格式不匹配直接返回,例如eth0\eth1可以
            return;
        }

        // If we don't already track this interface, and if this interface matches
        // our regex, start tracking it.
        if (mFactory.hasInterface(iface) || iface.equals(mDefaultInterface)) { //如果当前初始化过了该网卡直接返回
            if (DBG) Log.w(TAG, "Ignoring already-tracked interface " + iface);
            return;
        }
        if (DBG) Log.i(TAG, "maybeTrackInterface: " + iface);

        Intent intent = new Intent("android.net.action.ETH_DEVICE_ENABLED");
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
        Log.e(TAG, "Send broadcast: ETH_DEVICE_ENABLED");
        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);//发送广播,以太网设备可用

        // TODO: avoid making an interface default if it has configured NetworkCapabilities.
        //如果已配置NetworkCapabilities,请避免将接口设为默认接口。
        if (mDefaultInterface == null) {
            mDefaultInterface = iface;
        }

        if (mIpConfigForDefaultInterface != null) { //第一次时这块还是空的 所以没走这
            updateIpConfiguration(iface, mIpConfigForDefaultInterface);
            mIpConfigForDefaultInterface = null;
        }

        addInterface(iface);//执行下一步的方法
    }

addInterface

    private void addInterface(String iface) {
        InterfaceConfiguration config = null;
        // Bring up the interface so we get link status indications.
        try {
            mNMService.setInterfaceUp(iface);//先告诉netd加载上这个网卡并且获取配置
            config = mNMService.getInterfaceConfig(iface);
        } catch (RemoteException | IllegalStateException e) {
            // Either the system is crashing or the interface has disappeared. Just ignore the
            // error; we haven't modified any state because we only do that if our calls succeed.
            Log.e(TAG, "Error upping interface " + iface, e);
        }

        if (config == null) {
            Log.e(TAG, "Null interface config for " + iface + ". Bailing out.");
            return;
        }

        final String hwAddress = config.getHardwareAddress();

        NetworkCapabilities nc = mNetworkCapabilities.get(iface);//测试相关,先不管
        if (nc == null) {
            // Try to resolve using mac address
            nc = mNetworkCapabilities.get(hwAddress);
            if (nc == null) {
                final boolean isTestIface = iface.matches(TEST_IFACE_REGEXP);
                nc = createDefaultNetworkCapabilities(isTestIface);
            }
        }

        final int mode = getInterfaceMode(iface);//设置该网卡的这个模式,是客户端还是服务端
        if (mode == INTERFACE_MODE_CLIENT) {//一般都会走到这
            IpConfiguration ipConfiguration = mIpConfigurations.get(iface);
            if (ipConfiguration == null) {
                ipConfiguration = createDefaultIpConfiguration();//创建一个默认的数据对象
            }

            Log.d(TAG, "Tracking interface in client mode: " + iface);
            mFactory.addInterface(iface, hwAddress, nc, ipConfiguration);//继续调用该工厂类中的方法
        } else {
            maybeUpdateServerModeInterfaceState(iface, true);
        }

        // Note: if the interface already has link (e.g., if we crashed and got
        // restarted while it was running), we need to fake a link up notification so we
        // start configuring it.
        if (config.hasFlag("running")) {
            updateInterfaceState(iface, true);最后更新状态
        }
    }
EthernetNetworkFactory

frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetNetworkFactory.java
是时候看这个类了,之前在EthernetTracker的构造方法中就有他,现在我们来看
因为EthernetNetworkFactory注册了NetworkFactory 但是在子类并没有register方法,所以调的都是他父类的

public class EthernetNetworkFactory extends NetworkFactory {

来看其父类的注册方法都做了什么
frameworks/libs/net/common/src_servicescommon/android/net/NetworkFactory.java

    public void register() { //向系统注册此NetworkFactory。每个工厂只能调用一次
        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);//向connectivityService注册改回调函数,也就是和CONNECTIVITY_SERVICE进行交互
    }

所以上层fw的CONNECTIVITY_SERVICE服务到ethernet服务再到nmms(netd)服务之间的链路是这样来的
继续看EthernetNetworkFactory的构造方法

    public EthernetNetworkFactory(Handler handler, Context context, NetworkCapabilities filter) {
        super(handler.getLooper(), context, NETWORK_TYPE, filter);

        mHandler = handler;
        mContext = context;

        setScoreFilter(NETWORK_SCORE); //主要是设置分数,以太网的分数大于为wifi大于mobile
    }

回到初始化中的addInterface方法

        void addInterface(String ifaceName, String hwAddress, NetworkCapabilities capabilities,
             IpConfiguration ipConfiguration) {
        if (mTrackingInterfaces.containsKey(ifaceName)) {//如果当前打开的列表里有了,直接返回
            Log.e(TAG, "Interface with name " + ifaceName + " already exists.");
            return;
        }

        if (DBG) {
            Log.d(TAG, "addInterface, iface: " + ifaceName + ", capabilities: " + capabilities);
        }

        NetworkInterfaceState iface = new NetworkInterfaceState(//这个NetworkInterfaceState是个内部类
                ifaceName, hwAddress, mHandler, mContext, capabilities, this);
        iface.setIpConfig(ipConfiguration);//设置ip地址,等参数
        mTrackingInterfaces.put(ifaceName, iface);//放进容器内保存

        updateCapabilityFilter();//更新
    }

继续看

    private void updateCapabilityFilter() {
        NetworkCapabilities capabilitiesFilter = new NetworkCapabilities();
        capabilitiesFilter.clearAll();//清空

        for (NetworkInterfaceState iface:  mTrackingInterfaces.values()) {
            capabilitiesFilter.combineCapabilities(iface.mCapabilities);//根据现有打开的网卡初始化NetworkCapabilities对象
        }

        if (DBG) Log.d(TAG, "updateCapabilityFilter: " + capabilitiesFilter);
        setCapabilityFilter(capabilitiesFilter);//调用父类方法,第一次初始化不会执行具体的逻辑
    }

执行完这些之后,就可以回到EthernetTracker继续执行updateInterfaceState方法
frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetTracker.java

    private void updateInterfaceState(String iface, boolean up) {
        final int mode = getInterfaceMode(iface);
        final boolean factoryLinkStateUpdated = (mode == INTERFACE_MODE_CLIENT) //true
                && mFactory.updateInterfaceLinkState(iface, up);
                //调用EthernetNetworkFactory里边的updateInterfaceLinkState

        if (factoryLinkStateUpdated) { 
        //*如果给定接口被配置为受限(不具有NET_CAPABILITY_NOT_RESTRICED)功能,则返回true。否则,返回false。
            boolean restricted = isRestrictedInterface(iface);
            int n = mListeners.beginBroadcast();//开始广播
            for (int i = 0; i < n; i++) {
                try {
                    if (restricted) {
                        ListenerInfo listenerInfo = (ListenerInfo) mListeners.getBroadcastCookie(i);
                        if (!listenerInfo.canUseRestrictedNetworks) {
                            continue;
                        }
                    }
                    mListeners.getBroadcastItem(i).onAvailabilityChanged(iface, up);//执行网卡可用回调
                } catch (RemoteException e) {
                    // Do nothing here.
                }
            }
            mListeners.finishBroadcast();
        }
    }

前面会执行这里的updateInterfaceLinkState
frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetNetworkFactory.java

    /** Returns true if state has been modified */
    boolean updateInterfaceLinkState(String ifaceName, boolean up) {
        if (!mTrackingInterfaces.containsKey(ifaceName)) {//前面执行addInterface添加的,如果没有返回false,没有更新
            return false;
        }

        if (DBG) {
            Log.d(TAG, "updateInterfaceLinkState, iface: " + ifaceName + ", up: " + up);
        }

        NetworkInterfaceState iface = mTrackingInterfaces.get(ifaceName);
        return iface.updateLinkState(up);//执行内部类方法
    }
        /** Returns true if state has been modified */
        boolean updateLinkState(boolean up) {
            if (mLinkUp == up) return false; //不同状态才会执行
            mLinkUp = up;

            stop(); // (1)
            if (up) {
                start(); //(2)
            }

            return true;
        }

sotp() 就是把各种变量和状态清空

        void stop() {
            // Invalidate all previous start requests
            if (mIpClient != null) {
                shutdownIpClient(mIpClient);
                mIpClientCallback.awaitIpClientShutdown();
                mIpClient = null;
            }
            mIpClientCallback = null;

            if (mNetworkAgent != null) {
                mNetworkAgent.unregister();
                mNetworkAgent = null;
            }
            mLinkProperties.clear();
        }

IpClient下面有解释
start() 开始执行初始化网卡逻辑

        private void start() {
            if (mIpClient != null) {
                if (DBG) Log.d(TAG, "IpClient already started"); //之前已经初始化了就返回
                return;
            }
            if (DBG) {
                Log.d(TAG, String.format("Starting Ethernet IpClient(%s)", name));
            }

            mIpClientCallback = new IpClientCallbacksImpl();//与IpClient通信的回调
            IpClientUtil.makeIpClient(mContext, name, mIpClientCallback);
            mIpClientCallback.awaitIpClientStart(); //等待IpClient开启
            if (sTcpBufferSizes == null) {//缓存设置
                sTcpBufferSizes = mContext.getResources().getString(
                        com.android.internal.R.string.config_ethernet_tcp_buffers);
            }
            provisionIpClient(mIpClient, mIpConfig, sTcpBufferSizes);//设置各种网络参数
        }

provisionIpClient这个方法主要是进行网络具体参数的一些设置,但要依靠IpClient

        private static void provisionIpClient(IIpClient ipClient, IpConfiguration config,
                String tcpBufferSizes) {
            if (config.getProxySettings() == ProxySettings.STATIC ||
                    config.getProxySettings() == ProxySettings.PAC) {
                try {
                    ipClient.setHttpProxy(toStableParcelable(config.getHttpProxy()));//设置代理根据入参config中的参数
                } catch (RemoteException e) {
                    e.rethrowFromSystemServer();
                }
            }

            if (!TextUtils.isEmpty(tcpBufferSizes)) {
                try {
                    ipClient.setTcpBufferSizes(tcpBufferSizes);//不为空就设置
                } catch (RemoteException e) {
                    e.rethrowFromSystemServer();
                }
            }

            final ProvisioningConfiguration provisioningConfiguration;
            if (config.getIpAssignment() == IpAssignment.STATIC) {  //静态ip就设置咱们自己指定的
                provisioningConfiguration = new ProvisioningConfiguration.Builder()
                        .withStaticConfiguration(config.getStaticIpConfiguration())
                        .build();
            } else {
                provisioningConfiguration = new ProvisioningConfiguration.Builder()//动态ip就由系统自动生成
                        .withProvisioningTimeoutMs(0)
                        .build();
            }

            try {
                ipClient.startProvisioning(provisioningConfiguration.toStableParcelable());//最后调用IpClient开始设置
            } catch (RemoteException e) {
                e.rethrowFromSystemServer();
            }
        }
IpClientManager

frameworks/base/services/net/java/android/net/ip/IpClientManager.java

    /**
     * Start provisioning with the provided parameters.
     */
    public boolean startProvisioning(ProvisioningConfiguration prov) {
        final long token = Binder.clearCallingIdentity();
        try {
            mIpClient.startProvisioning(prov.toStableParcelable());
            return true;
        } catch (RemoteException e) {
            log("Error starting IpClient provisioning", e);
            return false;
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

这也不是具体实现,继续看

IpClient

packages/modules/NetworkStack/src/android/net/ip/IpClient.java

        @Override
        public void startProvisioning(ProvisioningConfigurationParcelable req) {
            enforceNetworkStackCallingPermission();
            IpClient.this.startProvisioning(ProvisioningConfiguration.fromStableParcelable(req));
        }

调用其内部类的方法

    /**
     * Start provisioning with the provided parameters.
     */
    public void startProvisioning(ProvisioningConfiguration req) {
        if (!req.isValid()) {
            doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
            return;
        }

        final ScanResultInfo scanResultInfo = req.mScanResultInfo;
        mCurrentBssid = null;
        if (scanResultInfo != null) {
            try {
                mCurrentBssid = MacAddress.fromString(scanResultInfo.getBssid());//获取并保存该网络的mac地址
            } catch (IllegalArgumentException e) {
                Log.wtf(mTag, "Invalid BSSID: " + scanResultInfo.getBssid()
                        + " in provisioning configuration", e);
            }
        }

        if (req.mLayer2Info != null) {
            mL2Key = req.mLayer2Info.mL2Key;
            mCluster = req.mLayer2Info.mCluster;
        }
        sendMessage(CMD_START, new android.net.shared.ProvisioningConfiguration(req));//发送msg
    }
                case CMD_START:
                    mConfiguration = (android.net.shared.ProvisioningConfiguration) msg.obj;//保存到本地
                    transitionTo(mClearingIpAddressesState);//转移状态,
                    break;

mClearingIpAddressesState是ClearingIpAddressesState这个内部类new出来的
先进入其enter方法

    class ClearingIpAddressesState extends State {
        @Override
        public void enter() {
            // Ensure that interface parameters are fetched on the handler thread so they are
            // properly ordered with other events, such as restoring the interface MTU on teardown.
            mInterfaceParams = mDependencies.getInterfaceParams(mInterfaceName);//在系统中获取该网卡的硬件参数
            if (mInterfaceParams == null) { //如果是空,改变成停止状态直接返回
                logError("Failed to find InterfaceParams for " + mInterfaceName);
                doImmediateProvisioningFailure(IpManagerEvent.ERROR_INTERFACE_NOT_FOUND);
                deferMessage(obtainMessage(CMD_STOP,
                        DisconnectCode.DC_INTERFACE_NOT_FOUND.getNumber()));
                return;
            }

            mLinkObserver.setInterfaceParams(mInterfaceParams);//设置参数

            if (readyToProceed()) {//查看是否有ip地址,这是true
                deferMessage(obtainMessage(CMD_ADDRESSES_CLEARED));//发送:自发自收
            } else {
                // Clear all IPv4 and IPv6 before proceeding to RunningState.
                // Clean up any leftover state from an abnormal exit from
                // tethering or during an IpClient restart.
                stopAllIP();
            }

            mCallback.setNeighborDiscoveryOffload(true);
        }
    }

发送CMD_ADDRESSES_CLEARED,看接收端

        @Override
        public boolean processMessage(Message msg) {
            switch (msg.what) {
                case CMD_ADDRESSES_CLEARED: //在这处理,改变状态。这里分析isUsingPreconnection为false的情况
                    transitionTo(isUsingPreconnection() ? mPreconnectingState : mRunningState);//直接进入mRunningState状态
                    break;

                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
                    handleLinkPropertiesUpdate(NO_CALLBACKS);
                    if (readyToProceed()) {
                        transitionTo(isUsingPreconnection() ? mPreconnectingState : mRunningState);
                    }
                    break;

                case CMD_STOP:
                case EVENT_PROVISIONING_TIMEOUT:
                    // Fall through to StartedState.
                    return NOT_HANDLED;

                default:
                    // It's safe to process messages out of order because the
                    // only message that can both
                    //     a) be received at this time and
                    //     b) affect provisioning state
                    // is EVENT_NETLINK_LINKPROPERTIES_CHANGED (handled above).
                    deferMessage(msg);
            }
            return HANDLED;
        }

        private boolean readyToProceed() {
            return !mLinkProperties.hasIpv4Address() && !mLinkProperties.hasGlobalIpv6Address();
        }

看一下RunningState的enter方法

        @Override
        public void enter() {
            ApfFilter.ApfConfiguration apfConfig = new ApfFilter.ApfConfiguration();
            apfConfig.apfCapabilities = mConfiguration.mApfCapabilities;
            apfConfig.multicastFilter = mMulticastFiltering;
            // Get the Configuration for ApfFilter from Context
            apfConfig.ieee802_3Filter = ApfCapabilities.getApfDrop8023Frames();
            apfConfig.ethTypeBlackList = ApfCapabilities.getApfEtherTypeBlackList();
            apfConfig.minRdnssLifetimeSec = mMinRdnssLifetimeSec;
            mApfFilter = ApfFilter.maybeCreate(mContext, apfConfig, mInterfaceParams, mCallback);
            // TODO: investigate the effects of any multicast filtering racing/interfering with the
            // rest of this IP configuration startup.
            if (mApfFilter == null) {
                mCallback.setFallbackMulticastFilter(mMulticastFiltering);
            }

            mPacketTracker = createPacketTracker();
            if (mPacketTracker != null) mPacketTracker.start(mConfiguration.mDisplayName);

            if (mConfiguration.mEnableIPv6 && !startIPv6()) {
                doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6);
                enqueueJumpToStoppingState(DisconnectCode.DC_ERROR_STARTING_IPV6);
                return;
            }

            if (mConfiguration.mEnableIPv4 && !isUsingPreconnection() && !startIPv4()) {//关键是这个startIPv4方法
                doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV4);
                enqueueJumpToStoppingState(DisconnectCode.DC_ERROR_STARTING_IPV4);
                return;
            }

            final InitialConfiguration config = mConfiguration.mInitialConfig;
            if ((config != null) && !applyInitialConfig(config)) {//应用初始化值,没有就跳过
                // TODO introduce a new IpManagerEvent constant to distinguish this error case.
                doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
                enqueueJumpToStoppingState(DisconnectCode.DC_INVALID_PROVISIONING);
                return;
            }

            if (mConfiguration.mUsingIpReachabilityMonitor && !startIpReachabilityMonitor()) {//默认不走这
                doImmediateProvisioningFailure(
                        IpManagerEvent.ERROR_STARTING_IPREACHABILITYMONITOR);
                enqueueJumpToStoppingState(DisconnectCode.DC_ERROR_STARTING_IPREACHABILITYMONITOR);
                return;
            }
        }

来看这个startIPv4()

    private boolean startIPv4() {
        // If we have a StaticIpConfiguration attempt to apply it and
        // handle the result accordingly.
        if (mConfiguration.mStaticIpConfig != null) {//预先分配的话走这
            if (mInterfaceCtrl.setIPv4Address(mConfiguration.mStaticIpConfig.getIpAddress())) {//继续去调mInterfaceCtrl
            //设置成功回调
                handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig));
            } else {
                return false;
            }
        } else {
            if (mDhcpClient != null) {
                Log.wtf(mTag, "DhcpClient should never be non-null in startIPv4()");
            }
            startDhcpClient();
        }

        return true;
    }
InterfaceController

packages/modules/NetworkStack/common/moduleutils/src/android/net/ip/InterfaceController.java

    /**
     * Set the IPv4 address of the interface.
     */
    public boolean setIPv4Address(final LinkAddress address) {
        return setInterfaceConfiguration(address, null);
    }

    /**
     * Set the IPv4 address and also optionally bring the interface up or down.
     */
    public boolean setInterfaceConfiguration(final LinkAddress ipv4Addr,
            final Boolean setIfaceUp) {
        if (!(ipv4Addr.getAddress() instanceof Inet4Address)) {//参数校验
            throw new IllegalArgumentException("Invalid or mismatched Inet4Address");
        }
        // Note: currently netd only support INetd#IF_STATE_UP and #IF_STATE_DOWN.
        // Other flags would be ignored.
        
		//参数包装,为了跨进程传递给netd
        final InterfaceConfigurationParcel ifConfig = new InterfaceConfigurationParcel();
        ifConfig.ifName = mIfName;
        ifConfig.ipv4Addr = ipv4Addr.getAddress().getHostAddress();
        ifConfig.prefixLength = ipv4Addr.getPrefixLength();
        // Netd ignores hwaddr in interfaceSetCfg.
        ifConfig.hwAddr = "";
        if (setIfaceUp == null) {//默认走这
            // Empty array means no change.
            ifConfig.flags = new String[0];
        } else {
            // Netd ignores any flag that's not IF_STATE_UP or IF_STATE_DOWN in interfaceSetCfg.
            ifConfig.flags = setIfaceUp.booleanValue()
                    ? new String[] {IF_STATE_UP} : new String[] {IF_STATE_DOWN};
        }
        try {
            mNetd.interfaceSetCfg(ifConfig);//接着把参数给到netd继续执行就可以了
        } catch (RemoteException | ServiceSpecificException e) {
            logError("Setting IPv4 address to %s/%d failed: %s",
                    ifConfig.ipv4Addr, ifConfig.prefixLength, e);
            return false;
        }
        return true;
    }

别忘了之前还有一个startIPv4()方法内还有个handleIPv4Success回调
packages/modules/NetworkStack/src/android/net/ip/IpClient.java

    private void handleIPv4Success(DhcpResults dhcpResults) {
        mDhcpResults = new DhcpResults(dhcpResults);//填充的分配好的ip地址
        final LinkProperties newLp = assembleLinkProperties();
        final int delta = setLinkProperties(newLp); //更新配置然后返回一个状态值,这个状态值会通知到其他监听该状态改变的类

        if (mDhcpResults.vendorInfo == null && detectUpstreamHotspotFromVendorIe()) {
            mDhcpResults.vendorInfo = DhcpPacket.VENDOR_INFO_ANDROID_METERED;
        }

        if (DBG) {
            Log.d(mTag, "onNewDhcpResults(" + Objects.toString(mDhcpResults) + ")");
            Log.d(mTag, "handleIPv4Success newLp{" + newLp + "}");
        }
        mCallback.onNewDhcpResults(mDhcpResults);//回调ip参数
        maybeSaveNetworkToIpMemoryStore();//空的

        dispatchCallback(delta, newLp);//重要是这里
    }
protected final IpClientCallbacksWrapper mCallback;

这个mCallback是IpClientCallbacksWrapper静态内部类
dispatchCallback开始分发配置结果

    private void dispatchCallback(int delta, LinkProperties newLp) {
        switch (delta) {
            case PROV_CHANGE_GAINED_PROVISIONING:
                if (DBG) {
                    Log.d(mTag, "onProvisioningSuccess()");
                }
                recordMetric(IpManagerEvent.PROVISIONING_OK);
                mCallback.onProvisioningSuccess(newLp); //如果正确设置后会走这
                break;

            case PROV_CHANGE_LOST_PROVISIONING:
                if (DBG) {
                    Log.d(mTag, "onProvisioningFailure()");
                }
                recordMetric(IpManagerEvent.PROVISIONING_FAIL);
                mCallback.onProvisioningFailure(newLp);
                break;

            default:
                if (DBG) {
                    Log.d(mTag, "onLinkPropertiesChange()");
                }
                mCallback.onLinkPropertiesChange(newLp);
                break;
        }
    }
    public static class IpClientCallbacksWrapper {
        private static final String PREFIX = "INVOKE ";
        private final IIpClientCallbacks mCallback;
       //...省略
        /**
         * Indicates that provisioning was successful.
         */
        public void onProvisioningSuccess(LinkProperties newLp) {
            log("onProvisioningSuccess({" + newLp + "})");
            try {
                mCallback.onProvisioningSuccess(mShim.makeSensitiveFieldsParcelingCopy(newLp));
            } catch (RemoteException e) {
                log("Failed to call onProvisioningSuccess", e);
            }
        }

最后则会回调到EthernetNetworkFactory中
frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetNetworkFactory.java

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

继续调到这

        void onIpLayerStarted(LinkProperties linkProperties) {
            if (mNetworkAgent != null) {
                Log.e(TAG, "Already have a NetworkAgent - aborting new request");
                stop(); //重复,直接返回
                return;
            }
            mLinkProperties = linkProperties;

            // Create our NetworkAgent.
            final NetworkAgentConfig config = new NetworkAgentConfig.Builder()
                    .setLegacyType(mLegacyType)
                    .setLegacyTypeName(NETWORK_TYPE) //ethernet
                    .build();
            mNetworkAgent = new NetworkAgent(mContext, mHandler.getLooper(), //初始化这个NetworkAgent对象
                    NETWORK_TYPE, mCapabilities, mLinkProperties,
                    getNetworkScore(), config, mNetworkFactory.getProvider()) {
                public void unwanted() {
                    if (this == mNetworkAgent) {
                        stop();
                    } else if (mNetworkAgent != null) {
                        Log.d(TAG, "Ignoring unwanted as we have a more modern " +
                                "instance");
                    }  // Otherwise, we've already called stop.
                }
            };
            mNetworkAgent.register();//注册到ConnectivityService
            mNetworkAgent.setLegacyExtraInfo(mHwAddress);
            mNetworkAgent.markConnected();  //建立链接
        }

参数申请完了就开始建立网络连接了,这一部分将放到下一章来讲
上层framework就分析到这,后续netd的部分如感兴趣可以自行了解

技术名词解释

IPClient
  • Android的IpClient是一个用于管理网络连接的类。它是Android系统中的一个重要组件,用于处理与网络连接相关的任务。IpClient负责获取IP地址、配置网络接口、处理DHCP请求和响应等操作。

  • IpClient使用了DHCP协议来获取IP地址。它会通过发送DHCP请求来与DHCP服务器进行通信,并获取分配给设备的IP地址、子网掩码、网关和DNS服务器等信息。一旦获取到这些信息,IpClient会将其配置到设备的网络接口上,使设备能够正常与网络进行通信。

  • 除了处理DHCP请求和响应外,IpClient还负责监测网络连接状态的变化。它会监听网络状态的改变,并在网络连接断开或重新连接时触发相应的操作。例如,当设备从无线网络切换到移动数据网络时,IpClient会重新获取IP地址并更新网络配置。

  • 总的来说,Android的IpClient是一个用于管理网络连接的重要组件,它通过DHCP协议获取IP地址并配置网络接口,同时监测网络连接状态的变化。这样可以确保设备能够顺畅地进行网络通信。

IpAssignment
  • 在Android中,可以使用IpAssignment枚举来设置IP地址分配模式。IpAssignment有以下几个选项:
  1. STATIC:静态IP地址分配模式。在这种模式下,你可以手动指定设备的IP地址、子网掩码、网关和DNS服务器。
  2. DHCP:动态主机配置协议(DHCP)模式。在这种模式下,设备会自动通过DHCP服务器获取IP地址、子网掩码、网关和DNS服务器。
LinkProperties

这个网络链接参数

/**
 * Describes the properties of a network link.
 *
 * A link represents a connection to a network.
 * It may have multiple addresses and multiple gateways,
 * multiple dns servers but only one http proxy and one
 * network interface.
 *
 * Note that this is just a holder of data.  Modifying it
 * does not affect live networks.
 *
 */
public final class LinkProperties implements Parcelable {
    // The interface described by the network link.
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
    private String mIfaceName;
    private final ArrayList<LinkAddress> mLinkAddresses = new ArrayList<>();
    private final ArrayList<InetAddress> mDnses = new ArrayList<>();
    // PCSCF addresses are addresses of SIP proxies that only exist for the IMS core service.
    private final ArrayList<InetAddress> mPcscfs = new ArrayList<InetAddress>();
    private final ArrayList<InetAddress> mValidatedPrivateDnses = new ArrayList<>();
    private boolean mUsePrivateDns;
    private String mPrivateDnsServerName;
    private String mDomains;
    private ArrayList<RouteInfo> mRoutes = new ArrayList<>();
    private Inet4Address mDhcpServerAddress;
    private ProxyInfo mHttpProxy;
    private int mMtu;
    // in the format "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max"
    private String mTcpBufferSizes;
    private IpPrefix mNat64Prefix;
    private boolean mWakeOnLanSupported;
    private Uri mCaptivePortalApiUrl;
    private CaptivePortalData mCaptivePortalData;
NetworkAgent

Android NetworkAgent 是一个用于管理网络连接的类。它允许应用程序在 Android 设备上监控和控制网络连接状态。NetworkAgent 可以用于创建、配置和管理网络连接,并提供与网络相关的信息。

通过 NetworkAgent,应用程序可以:

  • 监听网络连接状态的变化,例如连接建立、断开和切换连接等。
  • 获取当前活动的网络连接的详细信息,如网络类型、信号强度和 IP 地址等。
  • 请求建立新的网络连接或关闭现有的网络连接。
  • 设置网络连接的参数,如代理设置、数据使用限制和网络优先级等。
  • 使用 NetworkAgent API,开发人员可以实现更高级的网络管理功能,例如在多个网络之间自动切换、

小结

本章分析了安卓以太网这个模块的初始化流程,后续会对网卡的开启,路由的设置等网络策略进行分析

谢谢文章来源地址https://www.toymoban.com/news/detail-756185.html

到了这里,关于Android 11 Ethernet以太网架构分析(1)——初始化的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 触摸屏与PLC之间 EtherNet/IP无线以太网通信

    触摸屏与PLC之间 EtherNet/IP无线以太网通信

    在实际系统中,同一个车间里分布多台PLC,用触摸屏集中控制。通常所有设备距离在几十米到上百米不等。在有通讯需求的时候,如果布线的话,工程量较大耽误工期,这种情况下比较适合采用无线通信方式。 本方案以MCGS触摸屏和2台三菱FX5u PLC为例,介绍触摸屏与多台 PLC的

    2024年02月11日
    浏览(10)
  • 欧姆龙NJ/NX系列PLC 基于以太网的CIP通讯(EtherNet/IP)

    CIP (Common Industrial Protocol, 通用工业协议) 是由 ODVA组织提出并维护的具有增强服务的自动化通讯协议。是一种使用生产者-消费者通信模型的与媒体无关的协议,并且是上层的严格面向对象的协议。每个CIP对象都有属性(数据)、服务(命令)、连接和行为(属性值和服务之间

    2024年01月22日
    浏览(9)
  • Chapter 7 - 15. Congestion Management in Ethernet Storage Networks以太网存储网络的拥塞管理

    Congestion Notification in Routed Lossless Ethernet Networks End devices and their applications may not be aware of congestion in the network. A culprit device may continue to send (or solicit) more traffic on the network making the severity of congestion worse or increasing its duration. To solve this problem, the network switches can ‘explicitly’ notif

    2024年01月22日
    浏览(16)
  • Chapter 7 - 14. Congestion Management in Ethernet Storage Networks以太网存储网络的拥塞管理

    PFC Watchdog PFC watchdog works similarly to Pause timeout, but it only drops the traffic in the queue that is unable to transmit continuously for a timeout duration because of receiving PFC Pause frames. PFC 进程看门狗的工作原理与暂停超时类似,但它只会丢弃队列中因收到 PFC 暂停帧而无法在超时时间内连续传输的流量。

    2024年01月22日
    浏览(10)
  • FPGA平台以太网学习:涉及1G/2.5G Ethernet 和Tri Mode Ethernet MAC两个IP核的学习记录(一)——知识补给

    FPGA平台以太网学习:涉及1G/2.5G Ethernet 和Tri Mode Ethernet MAC两个IP核的学习记录(一)——知识补给

    学习不能稀里糊涂,要学会多思考,发散式学习以及总结: FPGA作为一种器件,只是实现目的的一种方法,过度追求实现的技术细节(用hdl还是hls,用啥芯片,用啥接口)容易只见树木不见森林。工具软件的用法也好,器件的架构也好,语言孰优孰劣的争论也罢。工程应用里大概

    2023年04月09日
    浏览(14)
  • FPGA平台以太网学习:涉及1G/2.5G Ethernet 和Tri Mode Ethernet MAC两个IP核的学习记录(三)——接口与框架

    FPGA平台以太网学习:涉及1G/2.5G Ethernet 和Tri Mode Ethernet MAC两个IP核的学习记录(三)——接口与框架

    学习不能稀里糊涂,要学会多思考,发散式学习以及总结:   FPGA作为一种器件,只是实现目的的一种方法,过度追求实现的技术细节(用hdl还是hls,用啥芯片,用啥接口)容易只见树木不见森林。工具软件的用法也好,器件的架构也好,语言孰优孰劣的争论也罢。工程应用里

    2024年02月09日
    浏览(33)
  • FPGA平台以太网学习:涉及1G/2.5G Ethernet 和Tri Mode Ethernet MAC两个IP核的学习记录(二)——IP学习使用

    FPGA平台以太网学习:涉及1G/2.5G Ethernet 和Tri Mode Ethernet MAC两个IP核的学习记录(二)——IP学习使用

      学习不能稀里糊涂,要学会多思考,发散式学习以及总结:   FPGA作为一种器件,只是实现目的的一种方法,过度追求实现的技术细节(用hdl还是hls,用啥芯片,用啥接口)容易只见树木不见森林。工具软件的用法也好,器件的架构也好,语言孰优孰劣的争论也罢。工程应

    2023年04月10日
    浏览(13)
  • [工业互联-12]:主流的工业以太网技术简介(PROFINET、POWERLINK、ETHERNET/IP、ETHERCAT、SERCOSIII、MODBUS TCP、CC-LINK IE)

    [工业互联-12]:主流的工业以太网技术简介(PROFINET、POWERLINK、ETHERNET/IP、ETHERCAT、SERCOSIII、MODBUS TCP、CC-LINK IE)

    目录 前言: 1、工业通信要求 1.1 工业通信网络分层模型 1.2 工业控制的实时性要求 2.  以太网技术 2.1 协议分层 2.2 实时应用 3. 常见工业以太网技术 3.1 PROFINET通信 3.2 POWERLINK通信 3.3 EtherNet/IP通信 3.4 EtherCAT通信 3.5 SERCOSIII通信 4.  工业以太网技术比较 4.1 市场占有 4.2 实时性

    2024年02月10日
    浏览(46)
  • 电子电器架构网络演化 —— 车载以太网TSN

    电子电器架构网络演化 —— 车载以太网TSN

    我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人

    2024年02月01日
    浏览(10)
  • wireshark以太网 MAC 帧分析

    wireshark以太网 MAC 帧分析

    注 1 : 正文区的目录结构。一级标题用阿拉伯数字大写,二级以下 ( 含 ) 用点分式阿拉伯数字。 注 2 :实验介绍及回答部分,均可图文并用;如用图,建议居中显示,并附上图标题 ( 编好图号 ) 一、 实验 目的 1.理解以太网 MAC 地址 2.学习并分析以太网 MAC 帧格式的结构、含

    2024年02月04日
    浏览(10)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包