EthernetMornitor 与 EthernetStateTracker
EthernetMornitor 这个类位于: frameworks/base/ethernet/java/android/net/ethernet/EthernetMonitor.java
它会监听底层ethernet 状态 的 event,对这些 event 做相应的处理,是EthernetStateTraker 的一个辅助,仅仅是network框架中一个微微微小的一部分。
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;
}
看完构造函数我们可以看出EthernetMonitor 和 EthernetStateTraker有着紧密的联系,接下来看看具体看函数分析二者之间的关系。
1.1 startMonitoring()
这个函数会在 EthernetStateTracker.StartPolling()中被调用,构建起了EthernetMonitor 和 EthernetStateTraker的联系。
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;
}
}
}
}
1.2 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;
}
}
1.3 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);
}
}
}
1.4 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);
}
}
3.1 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;
}
3.2 postNotification(int event)
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;
}