背景
Android kitkat 默认已经支持 Ethernet 有线网络,只要稍微配置,便可以直接使用,测试结果,网络浏览器和下载都没有没有问题,而且系统可以做到与 wifi 共存,互相不影响功能,这里简单介绍如何使能 Ethernet,并简要分析其代码和流程。
Linux 配置部分
Linux 需要能够支持有线网络,生成 eth 网络设备节点。
Android 配置
overlay
主要是 overlay 里面添加 Ethernet 网络类型支持: frameworks/base/core/res/res/values/config.xml
<string-array translatable="false" name="radioAttributes">
<item>"1,1"</item>
<item>"7,1"</item>
<item>"9,1"</item>
</string-array>
其中 9 对应 Ethernet 的网络类型,其定义在
ConnectivityManager.java 中
/**
* The Ethernet data connection. When active, all data traffic
* will use this network type's interface by default
* (it has a default route).
*/
public static final int TYPE_ETHERNET = 9;
init.<board>.rc
init 里面需要添加 dhcp 和 ip renew 服务
# DHCPCD
# # eth0
service dhcpcd_eth0 /system/bin/dhcpcd -ABKL
class main
disabled
oneshot
# IP Renew
# # eth0
service iprenew_eth0 /system/bin/dhcpcd -n
class main
disabled
oneshot
流程分析
ConnectivityService
ConnectivityService 的构造函数里面将会读取 radioAttributes 里面的网络配置
public ConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager,
NetworkFactory netFactory) {
if (DBG) log("ConnectivityService starting up");
// Load device network attributes from resources
String[] raStrings = context.getResources().getStringArray(
com.android.internal.R.array.radioAttributes);
for (String raString : raStrings) {
RadioAttributes r = new RadioAttributes(raString);
if (VDBG) log("raString=" + raString + " r=" + r);
if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) {
loge("Error in radioAttributes - ignoring attempt to define type " + r.mType);
continue;
}
if (mRadioAttributes[r.mType] != null) {
loge("Error in radioAttributes - ignoring attempt to redefine type " +
r.mType);
continue;
}
mRadioAttributes[r.mType] = r;
}
根据网络配置数据,将会创建 EthernetDataTracker , 并开始监听 startMonitoring
// Create and start trackers for hard-coded networks
for (int targetNetworkType : mPriorityList) {
final NetworkConfig config = mNetConfigs[targetNetworkType];
final NetworkStateTracker tracker;
try {
tracker = netFactory.createTracker(targetNetworkType, config);
mNetTrackers[targetNetworkType] = tracker;
} catch (IllegalArgumentException e) {
Slog.e(TAG, "Problem creating " + getNetworkTypeName(targetNetworkType)
+ " tracker: " + e);
continue;
}
tracker.startMonitoring(context, mTrackerHandler);
if (config.isDefault()) {
tracker.reconnect();
}
}
EthernetDataTracker
EthernetDataTracker 将会寻找第一个以 eth 开头的有线网络设备,打开并开始做 dhcp
<!-- Regex of wired ethernet ifaces -->
<string translatable="false" name="config_ethernet_iface_regex">eth\\d</string>
sIfaceMatch = context.getResources().getString(
com.android.internal.R.string.config_ethernet_iface_regex);
try {
final String[] ifaces = mNMService.listInterfaces();
for (String iface : ifaces) {
if (iface.matches(sIfaceMatch)) {
mNMService.setInterfaceUp(iface);
InterfaceConfiguration config = mNMService.getInterfaceConfig(iface);
if (getEthernetCarrierState(iface) == 1) {
mIface = iface;
mLinkUp = true;
mNetworkInfo.setIsAvailable(true);
if (config != null && mHwAddr == null) {
mHwAddr = config.getHardwareAddress();
if (mHwAddr != null) {
mNetworkInfo.setExtraInfo(mHwAddr);
}
}
}
// if a DHCP client had previously been started for this interface, then stop it
NetworkUtils.stopDhcp(iface);
}
}
reconnect();
} catch (RemoteException e) {
Log.e(TAG, "Could not get list of interfaces " + e);
}
DHCP 成功后,通知NetworkManagementService 网路已经连接,这个时候上层应用便可以开始执行网络操作。
mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr);
Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
msg.sendToTarget();
如果有多个网口呢,这个 EthernetDataTracker 显然不能满足要求,必须对其进行扩展。