EthernetMornitor 这个类位于: frameworks/base/ethernet/java/android/net/ethernet/EthernetMonitor.java
它会监听底层ethernet 状态 的 event.
1. EthernetMonitor :
/**
* Listens for events from kernel, and passes them on
* to the {@link EtherentStateTracker} for handling. Runs in its own thread.
*
* @hide
*/
public class EthernetMonitor {
private static final String TAG = "EthernetMonitor";
private static final int CONNECTED = 1;
private static final int DISCONNECTED = 2;
private static final int PHYUP = 3;
private static final String connectedEvent = "CONNECTED";
private static final String disconnectedEvent = "DISCONNECTED";
private static final int ADD_ADDR = 20;
private static final int RM_ADDR = 21;
private static final int NEW_LINK = 16;
private static final int DEL_LINK = 17;
private static final boolean localLOGV = false;
private EthernetStateTracker mTracker;
//EthernetMonitor 是 EthernetStateTraker 的一个辅助
public EthernetMonitor(EthernetStateTracker tracker) {
mTracker = tracker;
}
a. startMonitoring(): 会在 EthernetStateTracker.StartPolling()中 调用此函数。
public void startMonitoring() {
new MonitorThread().start(); //线程开始
}
class MonitorThread extends Thread {
public MonitorThread() {
super("EthMonitor");
}
public void run() {
//noinspection InfiniteLoopStatement
for (;;) { //不断的在监听 kernel event
int index;
int i;
int cmd;
String dev;
if (localLOGV) Slog.v(TAG, "go poll events");
String eventName = EthernetNative.waitForEvent(); //wait for event
if (eventName == null) {
continue;
}
if (localLOGV) Slog.v(TAG, "get event " + eventName);
/*
* Map event name into event enum
*/
i = 0;
while (i < eventName.length()) {
index = eventName.substring(i).indexOf(":");
if (index == -1)
break;
dev = eventName.substring(i, index);
i += index + 1;
index = eventName.substring(i).indexOf(":");
if (index == -1)
break;
cmd = Integer.parseInt(eventName.substring(i, i+index));
i += index + 1;
//dev 指eth0, cmd 是event参数。
if (localLOGV) Slog.v(TAG, "dev: " + dev + " ev " + cmd);
switch (cmd) {
case DEL_LINK: //断开连接
handleEvent(dev, DISCONNECTED);
break;
case ADD_ADDR: //添加IP address,即链接成功
handleEvent(dev, CONNECTED);
break;
case NEW_LINK: //phy up 状态
handleEvent(dev, PHYUP);
break;
}
}
}
}
b. handleEvent(String ifname,int event):
/**
* Handle all supplicant events except STATE-CHANGE
* @param event the event type
* @param remainder the rest of the string following the
* event name and " — "
*/
void handleEvent(String ifname,int event) {
switch (event) {
case DISCONNECTED:
mTracker.notifyStateChange(ifname,NetworkInfo.DetailedState.DISCONNECTED);
break;
case CONNECTED:
mTracker.notifyStateChange(ifname,NetworkInfo.DetailedState.CONNECTED);
break;
case PHYUP:
mTracker.notifyPhyConnected(ifname);
break;
default:
mTracker.notifyStateChange(ifname,NetworkInfo.DetailedState.FAILED);
break;
}
}
c. EthernetStateTraker.notifyStateChange():
public void notifyStateChange(String ifname,DetailedState state) {
if (localLOGV) Slog.i(TAG, "report new state " + state.toString() + " on dev " + ifname);
if (ifname.equals(mInterfaceName)) { //判断eth0名称是否正确
if (localLOGV) Slog.v(TAG, "update network state tracker");
synchronized(this) { //发送 Connected or Disconnected 消息
this.sendEmptyMessage(state.equals(DetailedState.CONNECTED)
? EVENT_HW_CONNECTED : EVENT_HW_DISCONNECTED);
}
}
}
d. EthernetStateTraker.notifyPhyConnected():
public void notifyPhyConnected(String ifname) {
if (localLOGV) Slog.v(TAG, "report interface is up for " + ifname);
synchronized(this) { //发送Phy connected 消息
this.sendEmptyMessage(EVENT_HW_PHYCONNECTED);
}
}
2. 发送消息之后,EthernetStateTraker 会handleMessage():
public void handleMessage(Message msg) {
synchronized (this) {
switch (msg.what) {
case EVENT_INTERFACE_CONFIGURATION_SUCCEEDED: //连接成功
if (localLOGV) Slog.i(TAG, "received configured succeeded, stack=" + mStackConnected + " HW=" + mHWConnected);
mStackConnected = true;
if (mHWConnected)
setState(true, msg.what);
break;
case EVENT_INTERFACE_CONFIGURATION_FAILED: //链接失败
mStackConnected = false;
//start to retry ?
break;
case EVENT_HW_CONNECTED: //HW连接上了
if (localLOGV) Slog.i(TAG, "received HW connected, stack=" + mStackConnected + " HW=" + mHWConnected);
mHWConnected = true;
if (mStackConnected)
setState(true, msg.what);
break;
case EVENT_HW_DISCONNECTED: //hw断开
if (localLOGV) Slog.i(TAG, "received disconnected events, stack=" + mStackConnected + " HW=" + mHWConnected);
setState(false, msg.what);
break;
case EVENT_HW_PHYCONNECTED: //phy 连上
if (localLOGV) Slog.i(TAG, "interface up event, kick off connection request");
if (!mStartingDhcp) {
int state = mEM.getState();
if (state != mEM.ETHERNET_STATE_DISABLED) {
EthernetDevInfo info = mEM.getSavedConfig(); //获得以前已有的连接IP
if (info != null && mEM.isConfigured()) {
try {
configureInterface(info); //配置IP
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
Slog.e(TAG, "Cannot configure interface");
}
}
}
}
setState(true, msg.what);
break;
}
}
}
3. setState(boolean state, int event):
private void setState(boolean state, int event) {
if (mNetworkInfo.isConnected() != state) {
if (state) { //connected or disconnected.
mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
} else {
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
stopInterface(true);
}
mNetworkInfo.setIsAvailable(state);
postNotification(event);
}
}
a. stopInterface():
/**
* Stop etherent interface
* @param suspend {@code false} disable the interface {@code true} only reset the connection without disable the interface
* @return true
*/
public boolean stopInterface(boolean suspend) {
if (mEM != null) {
EthernetDevInfo info = mEM.getSavedConfig();
if (info != null && mEM.isConfigured()) {
synchronized (mDhcpTarget) {
mInterfaceStopped = true;
if (localLOGV) Slog.i(TAG, "stop dhcp and interface");
// stop DhcpHandler Looper
mDhcpTarget.removeMessages(EVENT_DHCP_START);
String ifname = info.getIfName(); // eth0
if (!NetworkUtils.stopDhcp(ifname)) { //stop dhcpcd_eth0 service
if (localLOGV) Slog.w(TAG, "Could not stop DHCP");
}
//reset eth0, remove route and ip
NetworkUtils.resetConnections(ifname, NetworkUtils.RESET_ALL_ADDRESSES);
NetworkUtils.removeDefaultRoute(ifname);
mStartingDhcp = false;
if (!suspend) // if suspend = false, turn eth0 to down.
NetworkUtils.disableInterface(ifname);
mLinkProperties.clear();
}
}
}
return true;
}
b. postNotification(int event), 给ConnectivityService 发送 event state changed 消息.
private void postNotification(int event) {
Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, new NetworkInfo(mNetworkInfo));
msg.sendToTarget();
}
4. configureInterface(EthernetDevInfo info), 配置 IP 函数:
private boolean configureInterface(EthernetDevInfo info) throws UnknownHostException { mStackConnected = false; mHWConnected = false; mInterfaceStopped = false; mStartingDhcp = true; //DHCP 方式获得 IP if (info.getConnectMode().equals(EthernetDevInfo.ETHERNET_CONN_MODE_DHCP)) { if (localLOGV) Slog.i(TAG, "trigger dhcp for device " + info.getIfName()); sDnsPropNames = new String[] { "dhcp." + mInterfaceName + ".dns1", "dhcp." + mInterfaceName + ".dns2" }; mDhcpTarget.sendEmptyMessage(EVENT_DHCP_START); } else { //static IP 设置方式 int event; sDnsPropNames = new String[] { "net." + mInterfaceName + ".dns1", "net." + mInterfaceName + ".dns2" }; //从输入栏获取 ip, gateway, netmask, dns 值 mDhcpInfo1.ipAddress = lookupHost(info.getIpAddress()); mDhcpInfo1.gateway = lookupHost(info.getRouteAddr()); mDhcpInfo1.netmask = lookupHost(info.getNetMask()); mDhcpInfo1.dns1 = lookupHost(info.getDnsAddr()); mDhcpInfo1.dns2 = 0; if (localLOGV) Slog.i(TAG, "set ip manually " + mDhcpInfo1.toString()); //配置之前擦除以前的route NetworkUtils.removeDefaultRoute(info.getIfName()); //配置成功 if (NetworkUtils.configureInterface(info.getIfName(), mDhcpInfo1)) { event = EVENT_INTERFACE_CONFIGURATION_SUCCEEDED; SystemProperties.set("net.dns1", info.getDnsAddr()); SystemProperties.set("net." + info.getIfName() + ".dns1", info.getDnsAddr()); SystemProperties.set("net." + info.getIfName() + ".dns2", "0.0.0.0"); if (localLOGV) Slog.v(TAG, "Static IP configuration succeeded"); } else { //配置失败 event = EVENT_INTERFACE_CONFIGURATION_FAILED; if (localLOGV) Slog.w(TAG, "Static IP configuration failed"); } this.sendEmptyMessage(event); //给EthernetStateTracker发送message } return true; }
5. resetInterface(), 这个和stopInterface 差不多:/** * reset ethernet interface * @return true * @throws UnknownHostException */ public boolean resetInterface() throws UnknownHostException{ /* * This will guide us to enabled the enabled device */ if (mEM != null) { EthernetDevInfo info = mEM.getSavedConfig(); if (info != null && mEM.isConfigured()) { synchronized (this) { mInterfaceName = info.getIfName(); if (localLOGV) Slog.i(TAG, "reset device " + mInterfaceName); NetworkUtils.resetConnections(mInterfaceName, NetworkUtils.RESET_ALL_ADDRESSES); // Stop DHCP if (mDhcpTarget != null) { mDhcpTarget.removeMessages(EVENT_DHCP_START); } if (!NetworkUtils.stopDhcp(mInterfaceName)) { if (localLOGV) Slog.w(TAG, "Could not stop DHCP"); } mLinkProperties.clear(); configureInterface(info); //比stopInterface 多了一步 重新配置IP。 } } } return true; }