背景Android kitkat 預設已經支援 Ethernet 有線網路,只要稍微配置,便可以直接使用,測試結果,網路瀏覽器和下載都沒有沒有問題,而且系統可以做到與 wifi 共存,互相不影響功能,這裡簡單介紹如何使能 Ethernet,並簡要分析其代碼和流程。
Linux 配置部分
Linux 需要能夠支援有線網路,產生 eth 網路裝置節點。
Android 配置overlay
主要是 overlay 裡面添加 Ethernet 網路類型支援: frameworks/base/core/res/res/values/config.xml
"1,1" "7,1" "9,1"
其中 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..rc
init 裡面需要添加 dhcp 和 ip renew 服務
# DHCPCD# # eth0service dhcpcd_eth0 /system/bin/dhcpcd -ABKL class main disabled oneshot# IP Renew# # eth0service iprenew_eth0 /system/bin/dhcpcd -n class main disabled oneshot
流程分析
ConnectivityServiceConnectivityService 的建構函式裡面將會讀取 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(); } }
EthernetDataTrackerEthernetDataTracker 將會尋找第一個以 eth 開頭的有線網路裝置,開啟並開始做 dhcp
eth\\d
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 顯然不能滿足要求,必須對其進行擴充。