Lamdoc船长的宝藏:http://blog.youkuaiyun.com/lamdoc/article/category/1164160
android ethernet unplug/plug enable/disable 管理
android ethernet 管理, 可以分为两类:
1. 是网线插拔,unplug/plug。
unplug 时, eth0 可以up, 但是IP 必须为0, 因为打开internel时,必须快速出现连不上页面,而不是延迟好几十秒,才出现连不上。
plug in之后,IP 能自动恢复。
2. 是Setting里EthernetConfiguration 的勾选项。enable/disable。
disable ethernet 时, eth0 必须是down的, enable之后,才up,然后能自动恢复IP。
3. 是static ip configuration
IP
NETMASK
DNS
GATEWAY
4个IP选项,静态IP设置。
android ethernet 设计的几个模块
ethernet related files:
1. packages/app/Settings/: //Setting中添加选项代码
packages/apps/Settings/src/com/android/settings/ethernet/EthernetSettings.java
packages/apps/Settings/src/com/android/settings/ethernet/EthernetEnabler.java
packages/apps/Settings/src/com/android/settings/ethernet/EthernetConfigDialog.java
2. frameworks/base/ :
SystemUI: //状态栏(status_bar)显示部分代码
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java //现实statusbar
ConnectivityService:
frameworks/base/services/java/com/android/server/ConnectivityService.java //这里是ethernet部分程序的起始点
jni:
frameworks/base/core/jni/android_net_ethernet.cpp //新加的一些jni
本来就有的ethernet:
frameworks/base/services/java/com/android/server/EthernetService.java
frameworks/base/services/java/com/android/server/NetworkManagementService.java
frameworks/base/core/java/android/net/NetworkStats.java
新添加的ethernet:
frameworks/base/ethernet/* // 这是主要ethernet部分,java api 代码。
frameworks/base/ethernet/java/android/net/ethernet/EthernetManager.java
调试android ethernet 的常用命令
netcfg //查看ip情况
netcfg eth0 up dhcp //通过dhcp 自动获取ip和网关
2. ifconfig
ifconfig eth0 128.224.156.81 netmask 255.255.255.0 up
3. gateway 配置
route add default gw 192.168.0.1 dev eth0
4. dns 配置
echo "nameserver 128.224.160.11" > resolv.conf
nameserver 128.224.160.11
setprop net.dns1 128.224.160.11
setprop net.dns2 147.11.100.304. mac adddr
ifconfig eth0 hw ether 00:11:22:33:44:55
android ethernet的2个辅助模块 libnetutils 和 dhcpcd
1. 一个是 system/core/libnetutils/* , 即libnetutils.so 库. 这里面有两个.c经常会调用到
ifc_utils.c
dhcp_utils.c
java会 通过 JNI (CPP)再调用到 C代码
2. 第二个是 /external/dhcpcd/*, 生成/system/bin/dhcpcd.
这个是 守护进程 dhcpcd_eth0 会用到的工具。
ConnectivityService 中调用 EthernetStateTracker 和 EthernetService
u最近在研究android 中的 ethernet 部分,主要集中在上层JAVA service 和java api。
整个 android 系统的mobile, wifi,wimax 和 bluetooth 都是通过ConnectivitySerivice 来提供服务的。
android本身不自带ethernet服务,需要新加 android-x86 里拿的ics-ethernet patch。
接下来分析 ConnectivityService 是怎么提供 ethernet 服务的。
1. 最开始,ConnectivityService 中会创建 EthernetStateTracker 和 EthernetService。
frameworks/base/services/java/com/android/server/ConnectivityService.java:
- case ConnectivityManager.TYPE_ETHERNET:
- //mNetTrackers[netType] = EthernetDataTracker.getInstance();
- //mNetTrackers[netType].startMonitoring(context, mHandler);
- if(DBG) log("Starting Ethernet Service.");
- //创建 EthernetStateTracker
- EthernetStateTracker est=new EthernetStateTracker(context, mHandler);
- //创建EthernetService
- EthernetService ethService=new EthernetService(context, est);
- <PRE class=java name="code"> //向ServiceManager 中添加 ETHERNET_SERVICE 服务
- ServiceManager.addService(Context.ETHERNET_SERVICE, ethService);
- mNetTrackers[ConnectivityManager.TYPE_ETHERNET]= est; //赋值EthernetStateTracker.
- //调用EthernetStateTracker 的startMonitoring
- est.startMonitoring(context, mHandler);
- break;</PRE>
- <PRE></PRE>
- <P></P>
- <P style="BACKGROUND-COLOR: rgb(255,255,255)"><SPAN style="COLOR: #663300; FONT-SIZE: 16px"><STRONG><SPAN style="FONT-FAMILY: 宋体">a. mNetTrackers 定义:</SPAN></STRONG></SPAN></P>
- <P></P>
- <PRE class=java name="code"> /**
- * Sometimes we want to refer to the individual network state
- * trackers separately, and sometimes we just want to treat them
- * abstractly.
- */
- private NetworkStateTracker mNetTrackers[];
- //网络状态跟踪,no_connected, connecting, connected ,三种状态
- </PRE><BR>
- <P></P>
- <SPAN style="FONT-FAMILY: 宋体"><SPAN style="FONT-SIZE: 12px"><SPAN style="COLOR: #990000"><STRONG><SPAN style="FONT-SIZE: 16px"><SPAN style="BACKGROUND-COLOR: rgb(255,255,255); COLOR: #663300">b. EthernetStateTracker.startMonitoring():</SPAN><BR>
- </SPAN></STRONG></SPAN></SPAN></SPAN><PRE class=java name="code"> public void startMonitoring(Context context, Handler target) {
- if (localLOGV) Slog.v(TAG,"start to monitor the ethernet devices");
- if (mServiceStarted) { //获得systemService 中 ethernet_service的上下文
- mEM = (EthernetManager)context.getSystemService(Context.ETHERNET_SERVICE);
- mContext = context;
- mCsHandler = target;
- int state = mEM.getState();
- if (state != mEM.ETHERNET_STATE_DISABLED) {
- if (state == mEM.ETHERNET_STATE_UNKNOWN) {
- // maybe this is the first time we run, so set it to enabled
- mEM.setEnabled(mEM.getDeviceNameList() != null); //set mEM to enabled.
- } else {
- try {
- //if it's not the first time we run, reset the interface.
- resetInterface();
- } catch (UnknownHostException e) {
- Slog.e(TAG, "Wrong ethernet configuration");
- }
- }
- }
- }
- }
- </PRE><SPAN style="COLOR: #ff0000"><STRONG><SPAN style="FONT-SIZE: 16px"><BR>
- 2. 创建 EthernetStateTracker :</SPAN></STRONG></SPAN><SPAN style="FONT-SIZE: 16px"><BR>
- </SPAN>frameworks/base/ethernet/java/android/net/ethernet/EthernetStateTracker.java<BR>
- <BR>
- <DIV id=codeText class=codeText><PRE class=java name="code"> public EthernetStateTracker(Context context, Handler target){
- //创建 NetworkInfo,可以用来查看网络状况
- mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0,"ETH","");
- mLinkProperties = new LinkProperties(); //网络链接属性
- if (localLOGV) Slog.v(TAG,"Starts...");
- //EthernetNative 通过 JNI 调用到 libnetutil.so 中去了。
- if (EthernetNative.initEthernetNative()!= 0){
- Slog.e(TAG,"Can not init ethernet device layers");
- return;
- }
- if (localLOGV) Slog.v(TAG,"Successed");
- mServiceStarted = true;
- //创建 DHCP 线程
- HandlerThread dhcpThread = new HandlerThread("DHCP Handler Thread");
- dhcpThread.start();
- mDhcpTarget = new DhcpHandler(dhcpThread.getLooper(),this);
- mMonitor = new EthernetMonitor(this); //创建 EthernetMonitor
- mDhcpInfo = new DhcpInfoInternal(); //创建 DhcpInfoInternal, 用来描述DHCP IP配置
- mDhcpInfo1 = new DhcpInfo(); //创建DhcpInfo, 用来描述static ip 配置
- }</PRE><BR>
- <SPAN style="COLOR: #663300; FONT-SIZE: 16px"><STRONG>a. DhcpHandler(): <SPAN style="FONT-SIZE: 12px">
- 这个类不知道干啥的。。</SPAN></STRONG></SPAN><BR>
- <PRE class=java name="code"> private class DhcpHandler extends Handler {
- public DhcpHandler(Looper looper, Handler target) {
- super(looper);
- mTrackerTarget = target; //赋值mTrackerTarget.
- }
- </PRE><BR>
- <SPAN style="COLOR: #663300; FONT-SIZE: 16px"><STRONG>b. EthernetMonitor(): 这个会单独介绍<BR>
- <BR>
- c. DhcpInfoInternal(): 这个应该是DhcpInfo的新一代。</STRONG></SPAN><BR>
- frameworks/base/core/java/android/net/DhcpInfoInternal.java<BR>
- <BR>
- <PRE class=java name="code">/**
- * A simple object for retrieving the results of a DHCP request.
- * Replaces (internally) the IPv4-only DhcpInfo class.
- * @hide
- */
- public class DhcpInfoInternal {
- private final static String TAG = "DhcpInfoInternal";
- public String ipAddress;
- public int prefixLength;
- public String dns1;
- public String dns2;
- public String serverAddress;
- public int leaseDuration;
- private Collection<RouteInfo> mRoutes;
- </PRE><BR>
- <SPAN style="COLOR: #663300; FONT-SIZE: 16px"><STRONG>d. DhcpInfo 类内容明显 和 DhcpInfoInternal 不同:</STRONG></SPAN><BR>
- frameworks/base/core/java/android/net/DhcpInfo.java<BR>
- <PRE class=java name="code">/**
- * A simple object for retrieving the results of a DHCP request.
- */
- public class DhcpInfo implements Parcelable {
- public int ipAddress;
- public int gateway;
- public int netmask;
- public int dns1;
- public int dns2;
- public int serverAddress;
- public int leaseDuration;
- </PRE><BR>
- <BR>
- </DIV>
- <SPAN style="COLOR: #f00000; FONT-SIZE: 16px"><STRONG>3. <SPAN style="FONT-FAMILY: 宋体">
- 创建 </SPAN><SPAN style="FONT-FAMILY: 宋体">EthernetService</SPAN></STRONG></SPAN><SPAN style="FONT-SIZE: 16px">:</SPAN><BR>
- frameworks/base/services/java/com/android/server/EthernetService.java<BR>
- <BR>
- <PRE class=java name="code"> public EthernetService(Context context, EthernetStateTracker Tracker){
- mTracker = Tracker;
- mContext = context;
- isEnabled = getPersistedState();
- if (localLOGV==true) Slog.i(TAG,"Ethernet dev enabled "+ isEnabled);
- getDeviceNameList(); //从驱动获得设备表
- setState(isEnabled); //设置 enabled 状态
- Slog.d(TAG,"xxha: ---------------------- StartPolling()");
- mTracker.StartPolling(); //开始监听驱动层的事件信号
- }</PRE><BR>
- <SPAN style="COLOR: #663300"><STRONG><SPAN style="FONT-SIZE: 16px">a. getDeviceNameList() :</SPAN></STRONG></SPAN><BR>
- <PRE class=java name="code"> /**
- * get all the ethernet device names
- * @return interface name list on success, {@code null} on failure
- */
- public String[] getDeviceNameList() {
- return (scanDevice() > 0) ? DevName : null; //扫描设备
- }
- </PRE><BR>
- <PRE class=java name="code"> private int scanDevice() {
- int i, j;
- if ((i = EthernetNative.getInterfaceCnt()) == 0)
- return 0;
- DevName = new String[i];
- for (j = 0; j < i; j++) {
- DevName[j] = EthernetNative.getInterfaceName(j); //获取设备名eth0,sit0
- if (DevName[j] == null)
- break;
- if (localLOGV) Slog.v(TAG, "device " + j + " name " + DevName[j]);
- }
- return i;
- }
- </PRE><SPAN style="COLOR: #663300"><STRONG><SPAN style="FONT-SIZE: 16px"><BR>
- b. mTracker.StartPolling()</SPAN></STRONG></SPAN><BR>
- <PRE class=java name="code"> public void StartPolling() {
- mMonitor.startMonitoring(); //这个也会调到EthernetMonitor 中的 startMonitoring() 去。
- }
- </PRE><BR>
- <BR>
- <BR>
- <BR>
- <SPAN style="FONT-FAMILY: 宋体"><BR>
- <BR>
- </SPAN>
- <P></P>
- <PRE></PRE>
EthernetMornitor 与 EthernetStateTracker
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;
- }
/**
* 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;
- }
- }
- }
- }
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;
- }
- }
/**
* 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);
- }
- }
- }
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);
- }
- }
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;
- }
- }
- }
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);
- }
- }
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;
- }
/**
* 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();
- }
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;
- }
- <PRE></PRE><SPAN style="COLOR: #ff0000"><STRONG><SPAN style="FONT-SIZE: 16px">5. resetInterface(), 这个和stopInterface 差不多:</SPAN></STRONG></SPAN>
- <P></P>
- <P></P>
- <PRE class=java name="code"> /**
- * 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;
- }
- </PRE><BR>
- <BR>
- <P></P>
- <PRE></PRE>
- <PRE></PRE>
- <PRE></PRE>
- <PRE></PRE>
NetWorkUtils 和 android_net_NetUtils.cpp
EthernetStateTracker 中会,用到 NetWorkUtils 类中的一些函数, 这些函数,会调用JNI: android_net_NetUtils.cpp, 然后调到 libnetutils 库中去。
如:
NetworkUtils.disableInterface(ifname);
NetworkUtils.runDhcp(mInterfaceName, mDhcpInfo);
NetworkUtils.stopDhcp(mInterfaceName);
NetworkUtils.resetConnections(mInterfaceName, NetworkUtils.RESET_ALL_ADDRESSES);
NetworkUtils.configureInterface(info.getIfName(), mDhcpInfo1);
NetworkUtils.removeDefaultRoute(ifname);
等等。
1. NetworkUtils 类: frameworks/base/core/java/android/net/NetworkUtils.java
- /**
- * Native methods for managing network interfaces.
- *
- * {@hide}
- */
- public class NetworkUtils {
- private static final String TAG = "NetworkUtils";
- /** Bring the named network interface up. */
- public native static int enableInterface(String interfaceName);
- /** Bring the named network interface down. */
- public native static int disableInterface(String interfaceName);
- /** Remove the default route for the named interface. */
- public native static int removeDefaultRoute(String interfaceName);
- /** Setting bit 0 indicates reseting of IPv4 addresses required */
- public static final int RESET_IPV4_ADDRESSES = 0x01;
- /** Setting bit 1 indicates reseting of IPv4 addresses required */
- public static final int RESET_IPV6_ADDRESSES = 0x02;
- /** Reset all addresses */
- public static final int RESET_ALL_ADDRESSES = RESET_IPV4_ADDRESSES | RESET_IPV6_ADDRESSES;
- /**
- * Reset IPv6 or IPv4 sockets that are connected via the named interface.
- *
- * @param interfaceName is the interface to reset
- * @param mask {@see #RESET_IPV4_ADDRESSES} and {@see #RESET_IPV6_ADDRESSES}
- */
- public native static int resetConnections(String interfaceName, int mask);
- /**
- * Start the DHCP client daemon, in order to have it request addresses
- * for the named interface, and then configure the interface with those
- * addresses. This call blocks until it obtains a result (either success
- * or failure) from the daemon.
- * @param interfaceName the name of the interface to configure
- * @param ipInfo if the request succeeds, this object is filled in with
- * the IP address information.
- * @return {@code true} for success, {@code false} for failure
- */
- public native static boolean runDhcp(String interfaceName, DhcpInfoInternal ipInfo);
- /**
- * Initiate renewal on the Dhcp client daemon. This call blocks until it obtains
- * a result (either success or failure) from the daemon.
- * @param interfaceName the name of the interface to configure
- * @param ipInfo if the request succeeds, this object is filled in with
- * the IP address information.
- * @return {@code true} for success, {@code false} for failure
- */
- public native static boolean runDhcpRenew(String interfaceName, DhcpInfoInternal ipInfo);
- /**
- * Shut down the DHCP client daemon.
- * @param interfaceName the name of the interface for which the daemon
- * should be stopped
- * @return {@code true} for success, {@code false} for failure
- */
- public native static boolean stopDhcp(String interfaceName);
- /**
- * When static IP configuration has been specified, configure the network
- * interface according to the values supplied.
- * @param interfaceName the name of the interface to configure
- * @param ipInfo the IP address, default gateway, and DNS server addresses
- * with which to configure the interface.
- * @return {@code true} for success, {@code false} for failure
- */
- public static boolean configureInterface(String interfaceName, DhcpInfo ipInfo) {
- return configureNative(interfaceName,
- ipInfo.ipAddress,
- ipInfo.netmask,
- ipInfo.gateway,
- ipInfo.dns1,
- ipInfo.dns2);
- }
- private native static boolean configureNative(
- String interfaceName, int ipAddress, int netmask, int gateway, int dns1, int dns2);
/**
* Native methods for managing network interfaces.
*
* {@hide}
*/
public class NetworkUtils {
private static final String TAG = "NetworkUtils";
/** Bring the named network interface up. */
public native static int enableInterface(String interfaceName);
/** Bring the named network interface down. */
public native static int disableInterface(String interfaceName);
/** Remove the default route for the named interface. */
public native static int removeDefaultRoute(String interfaceName);
/** Setting bit 0 indicates reseting of IPv4 addresses required */
public static final int RESET_IPV4_ADDRESSES = 0x01;
/** Setting bit 1 indicates reseting of IPv4 addresses required */
public static final int RESET_IPV6_ADDRESSES = 0x02;
/** Reset all addresses */
public static final int RESET_ALL_ADDRESSES = RESET_IPV4_ADDRESSES | RESET_IPV6_ADDRESSES;
/**
* Reset IPv6 or IPv4 sockets that are connected via the named interface.
*
* @param interfaceName is the interface to reset
* @param mask {@see #RESET_IPV4_ADDRESSES} and {@see #RESET_IPV6_ADDRESSES}
*/
public native static int resetConnections(String interfaceName, int mask);
/**
* Start the DHCP client daemon, in order to have it request addresses
* for the named interface, and then configure the interface with those
* addresses. This call blocks until it obtains a result (either success
* or failure) from the daemon.
* @param interfaceName the name of the interface to configure
* @param ipInfo if the request succeeds, this object is filled in with
* the IP address information.
* @return {@code true} for success, {@code false} for failure
*/
public native static boolean runDhcp(String interfaceName, DhcpInfoInternal ipInfo);
/**
* Initiate renewal on the Dhcp client daemon. This call blocks until it obtains
* a result (either success or failure) from the daemon.
* @param interfaceName the name of the interface to configure
* @param ipInfo if the request succeeds, this object is filled in with
* the IP address information.
* @return {@code true} for success, {@code false} for failure
*/
public native static boolean runDhcpRenew(String interfaceName, DhcpInfoInternal ipInfo);
/**
* Shut down the DHCP client daemon.
* @param interfaceName the name of the interface for which the daemon
* should be stopped
* @return {@code true} for success, {@code false} for failure
*/
public native static boolean stopDhcp(String interfaceName);
/**
* When static IP configuration has been specified, configure the network
* interface according to the values supplied.
* @param interfaceName the name of the interface to configure
* @param ipInfo the IP address, default gateway, and DNS server addresses
* with which to configure the interface.
* @return {@code true} for success, {@code false} for failure
*/
public static boolean configureInterface(String interfaceName, DhcpInfo ipInfo) {
return configureNative(interfaceName,
ipInfo.ipAddress,
ipInfo.netmask,
ipInfo.gateway,
ipInfo.dns1,
ipInfo.dns2);
}
private native static boolean configureNative(
String interfaceName, int ipAddress, int netmask, int gateway, int dns1, int dns2);
2. android_net_NetUtils.cpp JNI 中的函数映射关系。
- /*
- * JNI registration.
- */
- static JNINativeMethod gNetworkUtilMethods[] = {
- /* name, signature, funcPtr */
- { "enableInterface", "(Ljava/lang/String;)I", (void *)android_net_utils_enableInterface },
- { "disableInterface", "(Ljava/lang/String;)I", (void *)android_net_utils_disableInterface },
- { "resetConnections", "(Ljava/lang/String;I)I", (void *)android_net_utils_resetConnections },
- { "removeDefaultRoute", "(Ljava/lang/String;)I", (void *)android_net_utils_removeDefaultRoute },
- { "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z", (void *)android_net_utils_runDhcp },
- { "runDhcpRenew", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z", (void *)android_net_utils_runDhcpRenew },
- { "stopDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_stopDhcp },
- { "releaseDhcpLease", "(Ljava/lang/String;)Z", (void *)android_net_utils_releaseDhcpLease },
- { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
- { "configureNative", "(Ljava/lang/String;IIIII)Z", (void *)android_net_utils_configureInterface },
- };
/*
* JNI registration.
*/
static JNINativeMethod gNetworkUtilMethods[] = {
/* name, signature, funcPtr */
{ "enableInterface", "(Ljava/lang/String;)I", (void *)android_net_utils_enableInterface },
{ "disableInterface", "(Ljava/lang/String;)I", (void *)android_net_utils_disableInterface },
{ "resetConnections", "(Ljava/lang/String;I)I", (void *)android_net_utils_resetConnections },
{ "removeDefaultRoute", "(Ljava/lang/String;)I", (void *)android_net_utils_removeDefaultRoute },
{ "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z", (void *)android_net_utils_runDhcp },
{ "runDhcpRenew", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z", (void *)android_net_utils_runDhcpRenew },
{ "stopDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_stopDhcp },
{ "releaseDhcpLease", "(Ljava/lang/String;)Z", (void *)android_net_utils_releaseDhcpLease },
{ "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
{ "configureNative", "(Ljava/lang/String;IIIII)Z", (void *)android_net_utils_configureInterface },
};
3. enableInterface(), diableInterface() , resetConnection():
- static jint android_net_utils_enableInterface(JNIEnv* env, jobject clazz, jstring ifname)
- {
- int result;
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- result = ::ifc_enable(nameStr); //这里就会调用到 libnetutils 中的 ifc_utils.c 去
- env->ReleaseStringUTFChars(ifname, nameStr);
- return (jint)result;
- }
- static jint android_net_utils_disableInterface(JNIEnv* env, jobject clazz, jstring ifname)
- {
- int result;
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- result = ::ifc_disable(nameStr);
- env->ReleaseStringUTFChars(ifname, nameStr);
- return (jint)result;
- }
- static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz,
- jstring ifname, jint mask)
- {
- int result;
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- LOGD("android_net_utils_resetConnections in env=%p clazz=%p iface=%s mask=0x%x\n",
- env, clazz, nameStr, mask);
- result = ::ifc_reset_connections(nameStr, mask);
- env->ReleaseStringUTFChars(ifname, nameStr);
- return (jint)result;
- }
static jint android_net_utils_enableInterface(JNIEnv* env, jobject clazz, jstring ifname)
{
int result;
const char *nameStr = env->GetStringUTFChars(ifname, NULL);
result = ::ifc_enable(nameStr); //这里就会调用到 libnetutils 中的 ifc_utils.c 去
env->ReleaseStringUTFChars(ifname, nameStr);
return (jint)result;
}
static jint android_net_utils_disableInterface(JNIEnv* env, jobject clazz, jstring ifname)
{
int result;
const char *nameStr = env->GetStringUTFChars(ifname, NULL);
result = ::ifc_disable(nameStr);
env->ReleaseStringUTFChars(ifname, nameStr);
return (jint)result;
}
static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz,
jstring ifname, jint mask)
{
int result;
const char *nameStr = env->GetStringUTFChars(ifname, NULL);
LOGD("android_net_utils_resetConnections in env=%p clazz=%p iface=%s mask=0x%x\n",
env, clazz, nameStr, mask);
result = ::ifc_reset_connections(nameStr, mask);
env->ReleaseStringUTFChars(ifname, nameStr);
return (jint)result;
}
4. runDhcp() , stopDhcp():
- static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstring ifname,
- jobject info, bool renew)
- {
- int result;
- char ipaddr[PROPERTY_VALUE_MAX];
- uint32_t prefixLength;
- char gateway[PROPERTY_VALUE_MAX];
- char dns1[PROPERTY_VALUE_MAX];
- char dns2[PROPERTY_VALUE_MAX];
- char server[PROPERTY_VALUE_MAX];
- uint32_t lease;
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- if (nameStr == NULL) return (jboolean)false;
- if (renew) {
- result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength,
- dns1, dns2, server, &lease);
- } else {
- result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,
- dns1, dns2, server, &lease); //调用 dhcp_utils.c 中的函数,获取route
- }
- env->ReleaseStringUTFChars(ifname, nameStr);
- if (result == 0) {
- env->SetObjectField(info, dhcpInfoInternalFieldIds.ipaddress, env->NewStringUTF(ipaddr));
- // set the gateway
- jclass cls = env->FindClass("java/net/InetAddress");
- jmethodID method = env->GetStaticMethodID(cls, "getByName",
- "(Ljava/lang/String;)Ljava/net/InetAddress;");
- jvalue args[1];
- args[0].l = env->NewStringUTF(gateway);
- jobject inetAddressObject = env->CallStaticObjectMethodA(cls, method, args);
- if (!env->ExceptionOccurred()) {
- cls = env->FindClass("android/net/RouteInfo");
- method = env->GetMethodID(cls, "<init>", "(Ljava/net/InetAddress;)V");
- args[0].l = inetAddressObject;
- jobject routeInfoObject = env->NewObjectA(cls, method, args);
- cls = env->FindClass("android/net/DhcpInfoInternal");
- method = env->GetMethodID(cls, "addRoute", "(Landroid/net/RouteInfo;)V");
- args[0].l = routeInfoObject;
- env->CallVoidMethodA(info, method, args);
- } else {
- // if we have an exception (host not found perhaps), just don't add the route
- env->ExceptionClear();
- }
- env->SetIntField(info, dhcpInfoInternalFieldIds.prefixLength, prefixLength);
- env->SetObjectField(info, dhcpInfoInternalFieldIds.dns1, env->NewStringUTF(dns1));
- env->SetObjectField(info, dhcpInfoInternalFieldIds.dns2, env->NewStringUTF(dns2));
- env->SetObjectField(info, dhcpInfoInternalFieldIds.serverAddress,
- env->NewStringUTF(server));
- env->SetIntField(info, dhcpInfoInternalFieldIds.leaseDuration, lease);
- }
- return (jboolean)(result == 0);
- }
static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstring ifname,
jobject info, bool renew)
{
int result;
char ipaddr[PROPERTY_VALUE_MAX];
uint32_t prefixLength;
char gateway[PROPERTY_VALUE_MAX];
char dns1[PROPERTY_VALUE_MAX];
char dns2[PROPERTY_VALUE_MAX];
char server[PROPERTY_VALUE_MAX];
uint32_t lease;
const char *nameStr = env->GetStringUTFChars(ifname, NULL);
if (nameStr == NULL) return (jboolean)false;
if (renew) {
result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength,
dns1, dns2, server, &lease);
} else {
result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,
dns1, dns2, server, &lease); //调用 dhcp_utils.c 中的函数,获取route
}
env->ReleaseStringUTFChars(ifname, nameStr);
if (result == 0) {
env->SetObjectField(info, dhcpInfoInternalFieldIds.ipaddress, env->NewStringUTF(ipaddr));
// set the gateway
jclass cls = env->FindClass("java/net/InetAddress");
jmethodID method = env->GetStaticMethodID(cls, "getByName",
"(Ljava/lang/String;)Ljava/net/InetAddress;");
jvalue args[1];
args[0].l = env->NewStringUTF(gateway);
jobject inetAddressObject = env->CallStaticObjectMethodA(cls, method, args);
if (!env->ExceptionOccurred()) {
cls = env->FindClass("android/net/RouteInfo");
method = env->GetMethodID(cls, "<init>", "(Ljava/net/InetAddress;)V");
args[0].l = inetAddressObject;
jobject routeInfoObject = env->NewObjectA(cls, method, args);
cls = env->FindClass("android/net/DhcpInfoInternal");
method = env->GetMethodID(cls, "addRoute", "(Landroid/net/RouteInfo;)V");
args[0].l = routeInfoObject;
env->CallVoidMethodA(info, method, args);
} else {
// if we have an exception (host not found perhaps), just don't add the route
env->ExceptionClear();
}
env->SetIntField(info, dhcpInfoInternalFieldIds.prefixLength, prefixLength);
env->SetObjectField(info, dhcpInfoInternalFieldIds.dns1, env->NewStringUTF(dns1));
env->SetObjectField(info, dhcpInfoInternalFieldIds.dns2, env->NewStringUTF(dns2));
env->SetObjectField(info, dhcpInfoInternalFieldIds.serverAddress,
env->NewStringUTF(server));
env->SetIntField(info, dhcpInfoInternalFieldIds.leaseDuration, lease);
}
return (jboolean)(result == 0);
}
- 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_runDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
- {
- return android_net_utils_runDhcpCommon(env, clazz, ifname, info, true);
- }
- static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname)
- {
- int result;
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- result = ::dhcp_stop(nameStr); // 这个调用 libnetutils 中的 dhcp_utils.c
- env->ReleaseStringUTFChars(ifname, nameStr);
- return (jboolean)(result == 0);
- }
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_runDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
{
return android_net_utils_runDhcpCommon(env, clazz, ifname, info, true);
}
static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname)
{
int result;
const char *nameStr = env->GetStringUTFChars(ifname, NULL);
result = ::dhcp_stop(nameStr); // 这个调用 libnetutils 中的 dhcp_utils.c
env->ReleaseStringUTFChars(ifname, nameStr);
return (jboolean)(result == 0);
}
5. 新添加的2个函数: removeDefaultRoute() 和 configureInterface():
- static jint android_net_utils_removeDefaultRoute(JNIEnv* env, jobject clazz, jstring ifname)
- {
- int result;
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- result = ::ifc_remove_default_route(nameStr);
- env->ReleaseStringUTFChars(ifname, nameStr);
- return (jint)result;
- }
- static jboolean android_net_utils_configureInterface(JNIEnv* env,
- jobject clazz,
- jstring ifname,
- jint ipaddr,
- jint mask,
- jint gateway,
- jint dns1,
- jint dns2)
- {
- int result;
- uint32_t lease;
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- result = ::ifc_configure(nameStr, ipaddr, mask, gateway, dns1, dns2);
- env->ReleaseStringUTFChars(ifname, nameStr);
- return (jboolean)(result == 0);
- }
static jint android_net_utils_removeDefaultRoute(JNIEnv* env, jobject clazz, jstring ifname)
{
int result;
const char *nameStr = env->GetStringUTFChars(ifname, NULL);
result = ::ifc_remove_default_route(nameStr);
env->ReleaseStringUTFChars(ifname, nameStr);
return (jint)result;
}
static jboolean android_net_utils_configureInterface(JNIEnv* env,
jobject clazz,
jstring ifname,
jint ipaddr,
jint mask,
jint gateway,
jint dns1,
jint dns2)
{
int result;
uint32_t lease;
const char *nameStr = env->GetStringUTFChars(ifname, NULL);
result = ::ifc_configure(nameStr, ipaddr, mask, gateway, dns1, dns2);
env->ReleaseStringUTFChars(ifname, nameStr);
return (jboolean)(result == 0);
}
6. libnetutils.so C 库导出来的 函数名, 这里主要用到了 ifc_utils.c 和 dhcp_utils.c 中的一些函数:
- extern "C" {
- int ifc_enable(const char *ifname);
- int ifc_disable(const char *ifname);
- int ifc_reset_connections(const char *ifname, int reset_mask);
- int ifc_remove_default_route(const char *ifname);
- int ifc_configure(const char *ifname,
- in_addr_t address,
- in_addr_t prefixLength,
- in_addr_t gateway,
- in_addr_t dns1,
- in_addr_t dns2);
- int dhcp_do_request(const char *ifname,
- const char *ipaddr,
- const char *gateway,
- uint32_t *prefixLength,
- const char *dns1,
- const char *dns2,
- const char *server,
- uint32_t *lease);
- int dhcp_do_request_renew(const char *ifname,
- const char *ipaddr,
- const char *gateway,
- uint32_t *prefixLength,
- const char *dns1,
- const char *dns2,
- const char *server,
- uint32_t *lease);
- int dhcp_stop(const char *ifname);
- int dhcp_release_lease(const char *ifname);
- char *dhcp_get_errmsg();
- }
dhcpcd守护进程分析
最近在调android ethernet功能,android本身不带 ethernet 功能,需要打patch。这个patch可以在setting里出来 ethernet configuration 选项。即添加了用户配置IP的功能。
我打上patch之后,点击选上DHCP功能,结果路由器一直不能自动分配IP。
经检测,命令行里运行 netcfg eth0 up dhcp 时,ethernet能被正常启动,DHCP能分配到IP。
但是Setting里选上时,dhcp却不能正常分配IP。 这很费解,我先后查看了,
/system/core/libnetutils/*
/externel/dhcpcd/*
发现都没什么问题。
在Setting中点击turn on ethernet选项时,从log看到能调到
- E/EthernetStateTracker( 185): DhcpHandler: DHCP request failed: Timed out waiting for dhcpcd to start
- D/EthernetStateTracker( 185): DhcpHandler: DHCP request started
说明patch是好的能正常工作,能正常掉用dhcp,只是DHCP运行不成功。
然后我查了 getprop: 显示 init.svc.dhcpcd_eth0 = stop
正常应该是running的,这样DHCP 才能运行成功。
最后调试了两天,才搞明白,原来是 init.rc 中 dhcpcd_eth0 守护进程的问题:
改成:
- on property:init.svc.dhcpcd_eth0=stopped
- start dhcpcd_eth0
- service dhcpcd_eth0 /system/bin/dhcpcd -ABKL -f /system/etc/dhcpcd/dhcpcd.conf -d eth0
- class main
- disabled
- oneshot
这样就可以了。
这时init.svc.dhcpcd_eth0 就会是 running 了。这时再点击Setting -> ethernet configuration, DHCP就能正常分配IP了。
libnetutils 和dhcpcd 调用过程如下:
1. libnetutils 调用过程:
- jni
- =>runDhcp
- =>android_net_utils_runDhcp
- libs/netutils/dhcp_utils.c
- =>dhcp_do_request
- =>
- static const char DAEMON_NAME[] = "dhcpcd";
- static const char DAEMON_PROP_NAME[] = "init.svc.dhcpcd";
- static const char DHCP_PROP_NAME_PREFIX[] = "dhcp";
- const char *ctrl_prop = "ctl.start";
- const char *desired_status = "running";
- snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
- DHCP_PROP_NAME_PREFIX,
- interface);
- property_set(result_prop_name, "");//设置dhcp.eth0.result="";等到成功完成dhcp之后,
- property_set(ctrl_prop, DAEMON_NAME);//向名字为dhcpcd的service,发送"ctrl.start"启动命令字,该service在init.rc中
- //init.rc中dhcpcd服务进程命令字
- //service dhcpcd /system/bin/dhcpcd eth0
- // disabled
- // oneshot
- wait_for_property(DAEMON_PROP_NAME, desired_status, 10);
- //init.c=>init进程
- //=>handle_property_set_fd因为是"ctrl.start"命令字,所以调用handle_control_message处理控制信息
- //=>handle_control_message
- //=>msg_start
- //=>
- // struct service *svc = service_find_by_name(name);
- // service_start(svc);//启动svc,即执行:/system/bin/dhcpcd eth0
- //=>service_start
- //=>pid = fork();
- // if(pid == 0)execve(svc->args[0], (char**) svc->args, (char**) ENV);子进程执行execve运行/system/bin/dhcpcd,参数为eth0
- //=>否则父进程,即init进程将
- //=>notify_service_state(svc->name, "running");设置该svc的状态prop
- // snprintf(pname, sizeof(pname), "init.svc.%s", name);
- // property_set(pname, state);//所以这样上面wait_for_property(DAEMON_PROP_NAME, desired_status, 10);也才能够正常pass[luther.gliethttp].
- wait_for_property(result_prop_name, NULL, 15);//等待dhcp.eth0.result=非空
2. dhcpcd 调用过程:
- system/extra/dhcpcd-4.0.0-beta9/dhcpcd.c
- dhcpcd
- =>main
- # define SYSCONFDIR "/system/etc/dhcpcd"
- #define PACKAGE "dhcpcd"
- # define CONFIG SYSCONFDIR "/" PACKAGE ".conf"
- # define LIBEXECDIR "/system/etc/dhcpcd"
- # define SCRIPT LIBEXECDIR "/" PACKAGE "-run-hooks"
- =>strlcpy(options->script, SCRIPT, sizeof(options->script));//默认的options->script="/system/etc/dhcpcd /dhcpcd-run-hooks"
- =>f = fopen(cf ? cf : CONFIG, "r");//如果没有指定.conf文件,那么使用默认.conf文件
- =>parse_config_line//解析"/system/etc/dhcpcd/dhcpcd.conf"默认配置文件
- =>parse_option
- =>如果在"/system/etc/dhcpcd/dhcpcd.conf"有"script"这个节
- =>那么执行strlcpy(options->script, oarg, sizeof(options->script));直接拷贝
- /*
- {"script", required_argument, NULL, 'c'},
- {"option", required_argument, NULL, 'o'},
- "/system/etc/dhcpcd/dhcpcd.conf"中的部分内容如下:
- ...
- option domain_name_servers, domain_name, domain_search, host_name
- ...
- */
- =>dhcp_run
- =>handle_dhcp_packet
- =>handle_dhcp
- =>bind_dhcp
- reason = "TIMEOUT";reason = "BOUND";reason = "REBIND";reason = "RENEW";
- system/extra/dhcpcd-4.0.0-beta9/configure.c
- => configure(iface, reason, state->new, state->old, &state->lease, options, 1);
- //如果dhcp超时或者dhcp成功,都会调用exec_script来执行脚本,
- //执行setprop dhcp.${interface}.result "failed"或者
- //执行setprop dhcp.${interface}.result "ok"
- =>exec_script(options, iface->name, reason, NULL, old);
- =>然后configure_env通过环境变量将reason传递到脚本中
- int exec_script(const struct options *options, const char *iface, const char *reason,
- const struct dhcp_message *dhcpn, const struct dhcp_message *dhcpo)
- =>pid = fork();
- =>if(pid == 0)execve(options->script, argv, env);//子进程执行脚本,默认"/system/etc/dhcpcd/dhcpcd-run-hooks"
- //dhcpcd-run-hooks脚本会根据level值,决定是否执行system/etc/dhcpcd/dhcpcd-hook/*目录下的相应文件
- //我们的系统在该system/etc/dhcpcd/dhcpcd-hook/*目录下有如下3个文件
- //95-configured
- //20-dns.conf
- //01-test
- =>父进程返回while (waitpid(pid, &status, 0) == -1)等待子进程脚本执行完成
- system/extra/dhcpcd-4.0.0-beta9/dhcpcd-hooks/20-dns.conf
- system/extra/dhcpcd-4.0.0-beta9/dhcpcd-hooks/95-configured
- ...
- setprop dhcp.${interface}.ipaddress "${new_ip_address}"
- setprop dhcp.${interface}.result "ok"//设置属性为ok
- setprop dhcp.${interface}.result "failed"
dhcpcd 工具
dhcpcd 源代码 位于 external/dhcpcd/*
这个目录的源代码生成 /system/bin/dhcpcd 命令工具和一些信息文件。
0605/external/dhcpcd$ ls *
android.conf CleanSpec.mk configure.h dhcpcd.conf dhcp.h if-linux.c logger.c NOTICE ThirdPartyProject.prop
Android.mk client.c control.c dhcpcd.conf.5 duid.c if-linux-wireless.c logger.h platform-bsd.c
arp.c client.h control.h dhcpcd.conf.5.in duid.h if-options.c lpf.c platform.h
arp.h common.c defs.h dhcpcd.h eloop.c if-options.h Makefile platform-linux.c
bind.c common.h dhcp.c dhcpcd-run-hooks eloop.h if-pref.c Makefile.inc README
bind.h config.h dhcpcd.8 dhcpcd-run-hooks.8 ifaddrs.c if-pref.h MODULE_LICENSE_BSD_LIKE showlease.c
bpf.c config.mk dhcpcd.8.in dhcpcd-run-hooks.8.in ifaddrs.h ipv4ll.c net.c signals.c
bpf-filter.h configure.c dhcpcd.c dhcpcd-run-hooks.in if-bsd.c ipv4ll.h net.h signals.h
compat:
arc4random.c arc4random.h closefrom.c closefrom.h getline.c getline.h linkaddr.c strlcpy.c strlcpy.h
dhcpcd-hooks:
01-test 10-mtu 20-resolv.conf 30-hostname 50-ntp.conf 50-yp.conf 95-configured
02-dump 20-dns.conf 29-lookup-hostname 50-dhcpcd-compat 50-ypbind 90-NetworkManager Makefile
mk:
cc.mk depend.mk dist.mk files.mk man.mk os-BSD.mk os-Darwin.mk os-Linux.mk os.mk prog.mk scripts.mk sys.mk
这里代码比较多,暂不细究了。