关于Android系统在开机后无法自动连接以太网的问题

Android系统版本:4.4

以太网卡:RTL8152B


最近有个客户说想要在android板上加入以太网功能,就在淘宝上先买了一个RTL8152的USB网卡(RTL8152本身就是USB接口的),就着手开始了移植工作


其实Android4.4已经支持以太网了,如果手上的android源码不支持以太网功能的话,就要自己移植代码,方法的话网上一抓一大把,我这里就不再赘述了


我需要做的只是在linux内核中将RTL8152的驱动加进去,将网卡接入板子的USB口,就可以开机看效果了


果然!果然!果然!果然!果然!果然!


开机之后发现以太网无法连接,就算执行了netcfg eth0 up dhcp也不行。

很奇怪的是执行了netcfg eth0 up dhcp这句代码后,使用ifconfig看网卡信息可以发现网卡已经自动获取到了ip地址,而且也可以ping通外网,可是使用浏览器却提示无法连接网络


我还尝试了将以太网连接的优先级设为0(本身为9),也还是不行


查看logcat发现在以太网卡启动的时候,有如下打印:

I/SystemServer(  501): Connectivity Service
I/ethernet(  501): ==>android_net_ethernet_initEthernetNative
D/ConnectivityService(  501): ConnectivityService starting up
D/ConnectivityService(  501): wifiOnly=false
D/ConnectivityService(  501): *******netType=wifi,1,1,1,-1,true
D/ConnectivityService(  501): *******netType=ethernet,9,9,0,-1,true
E/ConnectivityService(  501): Ignoring protectedNetwork 10
E/ConnectivityService(  501): Ignoring protectedNetwork 11
E/ConnectivityService(  501): Ignoring protectedNetwork 12
E/ConnectivityService(  501): Ignoring protectedNetwork 14
D/ConnectivityService(  501): *******targetNetworkType=1
I/EthernetStateTracker(  501): Starts...
I/EthernetStateTracker(  501): Success
I/ethernet(  501): User ask for device name on 0, total:1
I/ethernet(  501): Found :eth0
V/EthernetService(  501): Ethernet dev enabled 2
I/EthernetService(  501): total found 1 net devices
I/EthernetService(  501):  device 0 name eth0
I/EthernetService(  501): setEthState from 0 to 2
V/EthernetService(  501): Set ethernet mode [Ljava.lang.String;@41af6338 -> dhcp
D/NetUtils(  501): android_net_utils_resetConnections in env=0x415a6fb8 clazz=0x8f000019 iface=eth0 mask=0x3
I/EthernetService(  501): $$ EthernetService uninited,disable setEthState() call resetInterface()
I/EthernetService(  501): $$ resetInterface() will be called in reconnect()
V/EthernetService(  501): Trigger the ethernet monitor
V/EthernetStateTracker(  501): start polling
D/ConnectivityService(  501): *******targetNetworkType=9
I/EthernetStateTracker(  501): start to monitor the Ethernet devices
I/EthernetManager(  501): Init Ethernet Manager
I/EthernetStateTracker(  501): $$ DISABLE startMonitoring call resetInterface()
I/EthernetStateTracker(  501): >>>reconnect
I/EthernetService(  501): setEthState from 2 to 2
I/EthernetStateTracker(  501): $$reconnect call resetInterface()
I/EthernetStateTracker(  501): reset device eth0
V/AudioFlinger(  156): releaseWakeLock_l() AudioOut_2
V/AudioFlinger(  156): thread 0xb36d5008 type 0 TID 557 going to sleep
V/AudioFlinger(  156): releaseWakeLock_l() AudioOut_7
V/AudioFlinger(  156): releaseWakeLock_l() AudioOut_8
V/AudioFlinger(  156): thread 0xb3553008 type 0 TID 558 going to sleep
V/AudioFlinger(  156): thread 0xb3412008 type 2 TID 559 going to sleep
D/WifiHW  (  501): Unable to unload driver module "dhd": No such file or directory
I/EthernetStateTracker(  501): Force the connection disconnected before configuration
D/EthernetStateTracker(  501): setEthState state=false->false event=4



I/ethernet(  501): eth0: NEWLINK(16), flags=0X11043( LINK_UP MC RUNNING BC UP)
I/ethernet(  501): eth0:16:
E/ethernet(  501): netlink_route socket readable: [eth0:16:]
I/EthernetStateTracker(  501): report interface is up for eth0
D/EthernetStateTracker(  501): eth0 is not up!
I/EthernetStateTracker(  501): Old status stackConnected=false HWConnected=false
I/EthernetStateTracker(  501): [EVENT: Ether is up]
I/WifiService(  501): WifiService starting up with Wi-Fi disabled
D/EthernetService(  501): isEthernetDeviceAdded(eth0) return true
D/EthernetStateTracker(  501): setEthState state=false->false event=5
I/EthernetStateTracker(  501): New status, stackConnected=false HWConnected=true mStartingDhcp=false
D/EthernetStateTracker(  501): eth0 is not up!

可以看到以太网的服务是起来了,可是却无法使能eth0(?),其中关键的一句:

D/EthernetStateTracker(  501): eth0 is not up!

引起了我的注意,可是我想先试试别的方法


我又试着在Setting里为以太网设置静态ip,设置完之后发现可以联网,可见是dhcp出了问题

我又在开机状态下插拔了一下网线,发现可以上网了。。。。。


在各种百度GOOGLE无果后我开始自己研究


主要问题:为什么在开机过程中无法启动DHCP分配IP,而是要在开机后再插拔网线才能启动DHCP呢?


这下就要关注这句报错了:

eth0 is not up!


在Android源码的frameworks/base/ethernet/java/android/net/ethernet目录下可以找到EthernetStateTracker.java这个文件,“xxx is not up”就在这里:

private boolean configureInterface(EthernetDevInfo info) throws UnknownHostException {
........................

if (info.getConnectMode().equals(EthernetDevInfo.ETH_CONN_MODE_DHCP)) {
             if(mInterfaceName != null && !mEM.isEthernetDeviceUp(mInterfaceName)) {
                 Slog.d(TAG, mInterfaceName + " is not up!");
                 return false;
             }

........................
}


发现有个if判断,其中如果
if(mInterfaceName != null && !mEM.isEthernetDeviceUp(mInterfaceName))

为真的话,就会打印xxx is not up然后返回一个false,我试着屏蔽了这个return,发现板子一开机就可以自动联网了,DHCP也开启正常


耶!!!大功告成!!

。。。。。。。。。。。。。

事情当然没有那么简单,如果单单屏蔽这个return的话,系统就会在没有网线接入的情况下不断启动dhcp来自动获取ip,结果当然是失败的。而且系统会在调用失败后不停的继续调用dhcp这个功能,这样做当然是不严谨的。


我将mInterfaceName,EthernetDevInfo.ETH_CONN_MODE_DHCP,mEM.isEthernetDeviceUp(mInterfaceName)这三个参数打印了出来,发现

mInterfaceName = eth0

EthernetDevInfo.ETH_CONN_MODE_DHCP = dhcp

mEM.isEthernetDeviceUp(mInterfaceName) = false


看来问题就出在isEthernetDeviceUp这个方法调用上了


我与正常连接状态下的打印对比了一下,发现mEM.isEthernetDeviceUp(mInterfaceName) = true


接下来就追踪isEthernetDeviceUp方法,发现在frameworks/base/services/java/com/android/server目录下的EthernetService.java文件里:



看来系统判断以太网的状态是通过/sys/class/net/“ifname”/operstat这个设备节点来确定的

ifname是你的网络设备名,一般是eth0,也有可能是eth1


我在板子里输入命令:cat /sys/class/net/eth0/operstate,发现这个节点的状态是"unknown",拔掉网线,状态变为"down",再次插上网线,状态变为"up"

看来系统在开机时无法判断网络使能的情况,只有在系统启动后插拔网线,状态才能被检测到


我认为operstate这个节点保存的是以太网的运行状态,即是说当网线插入时,若禁止以太网功能,此节点的值仍然会变为"down"


而我的板子在系统启动之后operstate的值为"unknown",这就很奇怪了,可能是系统无法正常设置这个节点的值吧。

但是不用担心,在同一目录下还有另一个节点的值可供我们检测网线的插入状态,就是carrier。在网线插入时,carrier的之为1,网线拔出时,carrier的值为0。所以我们可以模仿isEthernetDeviceUp里的判断代码来另外写一个判断:

public boolean isEthernetDeviceUp(String ifname) {
    try {
        boolean retval = false;
        FileReader fr = new FileReader("/sys/class/net/" + ifname +"/operstate");
        BufferedReader br = new BufferedReader(fr, 32);
        String status = br.readLine();

        if (status != null && status.equals("up")) {
            Slog.d(TAG, ifname + " status:" + status);
            retval = true;
        }
        else if (status != null && status.equals("down")) {
            Slog.d(TAG, ifname + " status:" + status);
            retval = false;
        }
        else {
            retval =  false;
        }
	
/****************************Add Start****************************/	

		FileReader kFr = new FileReader("/sys/class/net/" + ifname + "/carrier");
		BufferedReader kBr = new BufferedReader(kFr, 32);
		String kStatus = kBr.readLine();
		if(kStatus != null && kStatus.equals("1")) {
			Slog.d(TAG, DevName[0] + " kStatus:" + kStatus);
			retval = true;
		}
		else if(kStatus != null && kStatus.equals("0")) {
			Slog.d(TAG, DevName[0] + " kStatus:" + kStatus);
			retval = false;
		}
		else {
			retval = false;
		}

		kBr.close();
		kFr.close();

/****************************Add End****************************/	
		
        br.close();
        fr.close();


        return retval;
    } catch (IOException e) {
        Slog.d(TAG, "get " + ifname + " status error");
        return false;
    }
}


此时,系统在检测完operstate的值之后就会继续去检测carrier的值,最后返回的结果是检测carrier的结果,大家如果喜欢的话可以将operstate的检测代码段屏蔽掉


这样修改之后系统就可以在启动的过程中就开启以太网功能并使用DHCP去自动获取IP地址,DNS等参数


OK,大功告成!


你可能感兴趣的:(Android系统,经验总结,安卓,以太网,Ethernet,无法上网,心得)