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!
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(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;
}
}
这样修改之后系统就可以在启动的过程中就开启以太网功能并使用DHCP去自动获取IP地址,DNS等参数
OK,大功告成!