Android4.4 以太網和DHCP啟動過程介紹


轉自:http://blog.csdn.net/wlwl0071986/article/details/51451843

Android4.4已經加入了以太網的支持。現在對以太網的初始化流程、網絡策略配置、dhcp交互過程等做一些簡單的介紹。

一、以太網啟動流程

1. 創建ConnectivityService

    SystemServer.Java

    // networkmanagement、networkStats、networkPolicy已經提前創建好,並作為參數傳入

    connectivity = new ConnectivityService(context,networkManagement,networkStats,networkPolicy);

 

2. 創建NetworkStateTracker和RadioAttributes

    ConnectivityService.java

    //會創建多個Tracker,包括wifi、bluetooth、mobile、ethernet等

    mNetTrackers = new NetworkStateTracker[ConnectivityManager.MAX_NETWORK_TYPE+1];

    mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1];

 

3. 加載網絡策略配置屬性

    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;
        }

 

4. 對已支持的網絡接口進行優先級排序

    mPriorityList = new int[mNetworksDefined];
        {
            int insertionPoint = mNetworksDefined-1;
            int currentLowest = 0;
            int nextLowest = 0;
            while (insertionPoint > -1) {
                for (NetworkConfig na : mNetConfigs) {
                    if (na == null) continue;
                    if (na.priority < currentLowest) continue;
                    if (na.priority > currentLowest) {
                        if (na.priority < nextLowest || nextLowest == 0) {
                            nextLowest = na.priority;
                        }
                        continue;
                    }
                    mPriorityList[insertionPoint--] = na.type;
                }
                currentLowest = nextLowest;
                nextLowest = 0;
            }
        }

 

5. 啟動已支持網絡接口的各個tracker

    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();
            }
        }

 

6. 啟動配置文件指定的以太網接口

    sIfaceMatch = context.getResources().getString(com.android.internal.R.string.config_ethernet_iface_regex);

    final String[] ifaces = mNMService.listInterfaces();

    // 如果指定的接口存在於網絡服務接口列表中,則通過該接口連接網絡

    if (iface.matches(sIfaceMatch)) {

        ...

        reconnect();

    }

 

7. 啟動DHCP服務

    public boolean reconnect() {
        if (mLinkUp) {
            mTeardownRequested.set(false);
            runDhcp();
        }
        return mLinkUp;
    }

   

    private void runDhcp() {
        Thread dhcpThread = new Thread(new Runnable() {
            public void run() {
                DhcpResults dhcpResults = new DhcpResults();
                if (!NetworkUtils.runDhcp(mIface, dhcpResults)) {

                    // 如果啟動DHCP服務失敗,則什么都不做退出
                    Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
                    return;
                }

                // 如果啟動DHCP服務成功,則設置對應的連接狀態,並通知其他網絡服務模塊更新狀態
                mLinkProperties = dhcpResults.linkProperties;

                mNetworkInfo.setIsAvailable(true);
                mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr);
                Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
                msg.sendToTarget();
            }
        });
        dhcpThread.start();
    }

 

8. 以太網的網絡策略配置

    frameworks\base\core\res\res\values-large\config.xml

    // 設置以太網的優先級,第四列數值越大、優先級越高

    <string-array translatable="false" name="networkAttributes">
        <item>"wifi,1,1,2,-1,true"</item>
        <item>"bluetooth,7,7,0,-1,true"</item>
        <item>"ethernet,9,9,9,-1,true"</item>
    </string-array>

 

    // 增加允許連接的網絡類型,9表示以太網接口
    <string-array translatable="false" name="radioAttributes">
        <item>"1,1"</item>
        <item>"7,1"</item>
        <item>"9,1"</item>
    </string-array>

 

    // 修改init.rc,增加以太網的service

    service dhcpcd_eth0 /system/bin/dhcpcd -ABDHKLd
        class main
        disabled
        oneshot

 

 

二、DHCP啟動過程

1. JNI層接口

    Java層調用的NetworkUtils.runDhcp(mIface, dhcpResults)接口,在android_net_Netutils.cpp中定義

        static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
        {
            return android_net_utils_runDhcpCommon(env, clazz, ifname, info, false);
        }

 

        static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz,

                                                         jstring ifname, jobject dhcpResults, bool renew)
        {

            ....

            if (renew) {
                result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength,
                dns, server, &lease, vendorInfo, domains, mtu);
            } else {
                result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,
                dns, server, &lease, vendorInfo, domains, mtu);
            }

            // 下面一段是將獲取到的ip地址字段存儲到JNI變量中供java層獲取,此處省略

            ....

        }

 

2. DHCP客戶端(libnetutils)

    dhcp_do_request接口定義在dhcp_utils.c中,該接口主要做了以下幾個工作:

    a. 啟動DHCP服務,並等待直至DHCP准備OK

        property_set(ctrl_prop, daemon_cmd);

        wait_for_property(daemon_prop_name, desired_status, 10)

    b. 等待DHCP服務端返回一個結果

        wait_for_property(result_prop_name, NULL, 30)

    c. 如果DHCP返回的結果狀態值為OK,則從DHCP服務端設置的全局屬性中讀取ip地址、網關等信息

        fill_ip_info(interface, ipaddr, gateway, prefixLength, dns, server, lease, vendorInfo, domain, mtu)

 

3. DHCP服務端(dhcpcd)

    a. DHCP消息類型

        DHCPDISCOVER

        DHCPOFFER

        DHCPREQUEST

        DHCPDECLINE

        DHCPACK

        DHCPNACK

        DHCPRELEASE

        DHCPINFORM

 

    b. DHCP的四步租約過程

       DHCP租約過程就是DHCP客戶機動態獲取IP地址的過程。

        ①客戶機請求IP(客戶機發DHCPDISCOVER廣播包)

                   當一個DHCP客戶機啟動時,會自動將自己的IP地址配置成0.0.0.0,由於使用0.0.0.0不能進行正常通

            信,所以客戶機就必須通過DHCP服務器來獲取一個合法的地址。由於客戶機不知道DHCP服務器的IP地址,

            所以它使用0.0.0.0的地址作為源地址,使用UDP68端口作為源端口,使用255.255.255.255作為目標地址,使

            用UDP67端口作為目的端口來廣播請求IP地址信息。廣播信息中包含了DHCP客戶機的MAC地址和計算機

            名,以便使DHCP服務器能確定是哪個客戶機發送的請求。

 

        ②服務器響應(服務器發DHCPOFFER廣播包)

                   當DHCP服務器接收到客戶機請求IP地址的信息時,它就在自己的IP地址池中查找是否有合法的IP地址提

            供給客戶機。如果有,DHCP服務器就將此IP地址做上標記,加入到DHCPOFFER的消息中,然后DHCP服務器

            就廣播一則包括下列信息的DHCPOFFER消息:

                 DHCP客戶機的MAC地址

                   DHCP服務器提供的合法IP地址

                   子網掩碼

                   默認網關(路由)

                   租約的期限

                   DHCP服務器的IP地址

            因為DHCP客戶機還沒有IP地址,所以DHCP服務器使用自己的IP地址作為源地址,使用UDP67端口作為源端

            口,使用255.255.255.255作為目標地址,使用UDP68端口作為目的端口來廣播DHCPOFFER信息。

 

        ③客戶機選擇IP(客戶機發DHCPREQUEST廣播包)

                 DHCP客戶機從接收到的第一個DHCPOFFER消息中選擇IP地址,發出IP地址的DHCP服務器將該地址保

            留,這樣該地址就不能提供給另一個DHCP客戶機。當客戶機從第一個DHCP服務器接收DHCPOFFER並選擇IP

            地址后,DHCP租約的第三過程發生。客戶機將DHCPREQUEST消息廣播到所有的DHCP服務器,表明它接受提

            供的內容。DHCPREQUEST消息包括為該客戶機提供IP配置的服務器的服務標識符(IP地址)。DHCP服務器

            查看服務器標識符字段,以確定它自己是否被選擇為指定的客戶機提供IP地址,如果那些DHCPOFFER被拒

            絕,則DHCP服務器會取消提供並保留其IP地址以用於下一個IP租約請求。

                   在客戶機選擇IP的過程中,雖然客戶機選擇了IP地址,但是還沒有配置IP地址,而在一個網絡中可能有幾

            個DHCP服務器,所以客戶機仍然使用0.0.0.0的地址作為源地址,使用UDP68端口作為源端口,使用

             255.255.255.255作為目標地址,使用UDP67端口作為目的端口來廣播DHCPREQUEST信息。

 

        ④服務器確定租約(服務器發DHCPACK/DHCPNAK廣播包)

                 DHCP服務器接收到DHCPREQUEST消息后,以DHCPACK消息的形式向客戶機廣播成功的確認,該消息包

            含有IP地址的有效租約和其他可能配置的信息。雖然服務器確認了客戶機的租約請求,但是客戶機還沒有收

            到服務器的DHCPACK消息,所以服務器仍然使用自己的IP地址作為源地址,使用UDP67端口作為源端口,使

            用255.255.255.255作為目標地址,使用UDP68端口作為目的端口來廣播DHCPACK信息。當客戶機收到

           DHCPACK消息時,它就配置了IP地址,完成了TCP/IP的初始化。

                   如果DHCPREQUEST不成功,例如客戶機試圖租約先前的IP地址,但該IP地址不再可用,或者因為客戶機

            移到其他子網,該IP無效時,DHCP服務器將廣播否定確認消息DHCPNAK。當客戶機接收到不成功的確認時,

            它將重新開始DHCP租約過程。

                   如果DHCP客戶機無法找到DHCP服務器,它將從TCP/IP的B類網段169.254.0.0中挑選一個IP地址作為自

            己的IP地址,繼續每隔5分鍾嘗試與DHCP服務器進行通訊,一旦與DHCP服務器取得聯系,則客戶機放棄自

            動配置的IP地址,而使用DHCP服務器分配的IP地址。

 

    c. DHCP客戶機向網絡DHCP服務器租約IP地址的流程及實際log

        dhcpcd[1544]: version 5.5.6 starting
        dhcpcd[1544]: get_duid: Permission denied
        dhcpcd[1544]: eth0: using ClientID 01:12:78:e4:0b:44:00
        dhcpcd[1544]: eth0: executing `/system/etc/dhcpcd/dhcpcd-run-hooks', reason PREINIT
        dhcpcd[1544]: eth0: reading lease `/data/misc/dhcp/dhcpcd-eth0.lease'
        dhcpcd[1544]: eth0: rebinding lease of 192.168.4.164
        dhcpcd[1544]: eth0: sending REQUEST (xid 0x440be4), next in 3.54 seconds
        dhcpcd[1544]: eth0: sending REQUEST (xid 0x440be4), next in 7.63 seconds
        dhcpcd[1544]: eth0: NAK: from 192.168.4.1
        dhcpcd[1544]: eth0: executing `/system/etc/dhcpcd/dhcpcd-run-hooks', reason NAK
        dhcpcd[1544]: eth0: broadcasting for a lease
        dhcpcd[1544]: eth0: sending DISCOVER (xid 0x440be4), next in 4.97 seconds
        dhcpcd[1544]: eth0: offered 192.168.4.165 from 192.168.4.1
        dhcpcd[1544]: eth0: sending REQUEST (xid 0x440be4), next in 3.02 seconds
        dhcpcd[1544]: eth0: acknowledged 192.168.4.165 from 192.168.4.1
        dhcpcd[1544]: eth0: leased 192.168.4.165 for 7200 seconds
        dhcpcd[1544]: eth0: adding IP address 192.168.4.165/24
        dhcpcd[1544]: eth0: adding route to 192.168.4.0/24
        dhcpcd[1544]: eth0: adding default route via 192.168.4.1
        dhcpcd[1544]: eth0: writing lease `/data/misc/dhcp/dhcpcd-eth0.lease'
        dhcpcd[1544]: eth0: executing `/system/etc/dhcpcd/dhcpcd-run-hooks', reason BOUND

 

    d. 調試網絡的常用命令

        (1) netcfg
             netcfg   //查看ip情況
             netcfg eth0 up dhcp   //通過dhcp 自動獲取ip和網關
 
        (2) ifconfig
             ifconfig eth0 192.168.8.81 up
             ifconfig eth0 192.168.8.81 netmask 255.255.255.0 up
 
        (3) gateway 配置
             route add default gw 192.168.0.1 dev eth0
 
        (4) dns 配置
             setprop net.dns1 192.168.8.11
             setprop net.dns2 147.11.100.30
 
        (5) mac adddr
             ifconfig eth0 hw ether 00:AA:BB:33:44:55

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM