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,开发人员可以实现更高级的网络管理功能,例如在多个网络之间自动切换、

小结

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

谢谢

  • 9
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Android 11 中,双以太网同时联网的实现需要借助 NetworkStack 和 Ethernet 管理器。下面是一个简单的代码示例: 1. 获取 Ethernet 管理器实例: ``` EthernetManager ethernetManager = (EthernetManager) context.getSystemService(Context.ETHERNET_SERVICE); ``` 2. 创建两个 Ethernet 连接: ``` EthernetManager.EthernetNetworkCallback callback1 = new EthernetManager.EthernetNetworkCallback() { // 处理网络连接状态变化 }; EthernetNetworkSpecifier specifier1 = new EthernetNetworkSpecifier.Builder() .setMacAddress(MacAddress.fromString("xx:xx:xx:xx:xx:xx")) .build(); ethernetManager.requestNetwork(specifier1, callback1); EthernetManager.EthernetNetworkCallback callback2 = new EthernetManager.EthernetNetworkCallback() { // 处理网络连接状态变化 }; EthernetNetworkSpecifier specifier2 = new EthernetNetworkSpecifier.Builder() .setMacAddress(MacAddress.fromString("xx:xx:xx:xx:xx:xx")) .build(); ethernetManager.requestNetwork(specifier2, callback2); ``` 其中,`MacAddress.fromString()` 方法需要传入对应的 MAC 地址。 3. 获取 NetworkStack 实例: ``` NetworkStackClient networkStackClient = NetworkStackClient.getInstance(); ``` 4. 创建两个网络接口: ``` InetAddress ipv4Address1 = InetAddress.getByName("192.168.0.100"); InetAddress ipv4Address2 = InetAddress.getByName("192.168.1.100"); int interface1 = networkStackClient.createEthernetNetworkInterface(specifier1, ipv4Address1); int interface2 = networkStackClient.createEthernetNetworkInterface(specifier2, ipv4Address2); ``` 5. 将网络接口添加到路由表中: ``` NetworkStack.setInterfaceIpv4Address(interface1, ipv4Address1, 24); NetworkStack.addRoute(interface1, InetAddress.getByName("0.0.0.0"), 0); NetworkStack.setInterfaceIpv4Address(interface2, ipv4Address2, 24); NetworkStack.addRoute(interface2, InetAddress.getByName("0.0.0.0"), 0); ``` 6. 完成以上步骤后,两个以太网就可以同时联网了。 需要注意的是,这只是一个简单的示例代码,实际运行时需要根据具体情况进行修改和优化。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值