首页 > 代码库 > Android 4.4 Kitkat 使能有线网络 Ethernet

Android 4.4 Kitkat 使能有线网络 Ethernet

背景

Android kitkat 默认已经支持 Ethernet 有线网络,只要稍微配置,便可以直接使用,测试结果,网络浏览器和下载都没有没有问题,而且系统可以做到与 wifi 共存,互相不影响功能,这里简单介绍如何使能 Ethernet,并简要分析其代码和流程。

Linux 配置部分


Linux 需要能够支持有线网络,生成 eth 网络设备节点。

Android 配置

overlay


主要是 overlay 里面添加 Ethernet 网络类型支持:  frameworks/base/core/res/res/values/config.xml 
    <string-array translatable="false" name="radioAttributes">
        <item>"1,1"</item>
        <item>"7,1"</item>
        <item>"9,1"</item>
    </string-array>

其中 9 对应 Ethernet 的网络类型,其定义在 ConnectivityManager.java 中
    /**
     * The Ethernet data connection.  When active, all data traffic
     * will use this network type's interface by default
     * (it has a default route).
     */
    public static final int TYPE_ETHERNET    = 9;

init.<board>.rc


init 里面需要添加 dhcp 和 ip renew 服务
# DHCPCD
# # eth0
service dhcpcd_eth0 /system/bin/dhcpcd -ABKL
    class main
    disabled
    oneshot

# IP Renew
# # eth0
service iprenew_eth0 /system/bin/dhcpcd -n
    class main
    disabled
    oneshot

流程分析


ConnectivityService

ConnectivityService 的构造函数里面将会读取 radioAttributes 里面的网络配置
    public ConnectivityService(Context context, INetworkManagementService netManager,
            INetworkStatsService statsService, INetworkPolicyManager policyManager,
            NetworkFactory netFactory) {
        if (DBG) log("ConnectivityService starting up");

        // Load device network attributes from resources
        String[] raStrings = context.getResources().getStringArray(
                com.android.internal.R.array.radioAttributes);
        for (String raString : raStrings) {
            RadioAttributes r = new RadioAttributes(raString);
            if (VDBG) log("raString=" + raString + " r=" + r);
            if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) {
                loge("Error in radioAttributes - ignoring attempt to define type " + r.mType);
                continue;
            }
            if (mRadioAttributes[r.mType] != null) {
                loge("Error in radioAttributes - ignoring attempt to redefine type " +
                        r.mType);
                continue;
            }
            mRadioAttributes[r.mType] = r;
        }

根据网络配置数据,将会创建 EthernetDataTracker , 并开始监听 startMonitoring
        // Create and start trackers for hard-coded networks
        for (int targetNetworkType : mPriorityList) {
            final NetworkConfig config = mNetConfigs[targetNetworkType];
            final NetworkStateTracker tracker;
            try {
                tracker = netFactory.createTracker(targetNetworkType, config);
                mNetTrackers[targetNetworkType] = tracker;
            } catch (IllegalArgumentException e) {
                Slog.e(TAG, "Problem creating " + getNetworkTypeName(targetNetworkType)
                        + " tracker: " + e);
                continue;
            }

            tracker.startMonitoring(context, mTrackerHandler);
            if (config.isDefault()) {
                tracker.reconnect();
            }
        }


EthernetDataTracker

EthernetDataTracker 将会寻找第一个以 eth 开头的有线网络设备,打开并开始做 dhcp

    <!-- Regex of wired ethernet ifaces -->
    <string translatable="false" name="config_ethernet_iface_regex">eth\\d</string>

        sIfaceMatch = context.getResources().getString(
                          com.android.internal.R.string.config_ethernet_iface_regex);
        try {
            final String[] ifaces = mNMService.listInterfaces();
            for (String iface : ifaces) {
                if (iface.matches(sIfaceMatch)) {
                    mNMService.setInterfaceUp(iface);
                    InterfaceConfiguration config = mNMService.getInterfaceConfig(iface);

                    if (getEthernetCarrierState(iface) == 1) {
                        mIface = iface;
                        mLinkUp = true;
                        mNetworkInfo.setIsAvailable(true);

                        if (config != null && mHwAddr == null) {
                            mHwAddr = config.getHardwareAddress();

                            if (mHwAddr != null) {
                                mNetworkInfo.setExtraInfo(mHwAddr);
                            }
                        }
                    }

                    // if a DHCP client had previously been started for this interface, then stop it
                    NetworkUtils.stopDhcp(iface);
                }
            }

            reconnect();
        } catch (RemoteException e) {
            Log.e(TAG, "Could not get list of interfaces " + e);
        }

DHCP 成功后,通知NetworkManagementService  网路已经连接,这个时候上层应用便可以开始执行网络操作。

                mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr);
                Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
                msg.sendToTarget();

如果有多个网口呢,这个 EthernetDataTracker 显然不能满足要求,必须对其进行扩展。