最近在在5.1移植了以太網過來,移植的過程並沒有什麼大問題,修改了框架上的代以及添加了Settings代碼,以太網調試就基本完工了,後面只是修改下佈局即可。但是網絡切換策略就有所變化了,就不得不重新認識5.1的網絡切換策略了。
在android4.4上,想實現以太網爲優先級最高(意思是以太網打開了,WIFI就無法打開),方法很簡單,只需要在default.xml和ConnectivityServicet修改就好了。但在5.1系統上就做了新的調整,具體改動的原因不明,他是依靠網絡評分的大小來確定誰的優先級高,廢話不多說,以以太網爲例子,進行追蹤。
1、frameworks\opt\net\ethernet\java\com\android\server\ethernet\EthernetServiceImpl
public EthernetServiceImpl(Context context) {
mContext = context;
Log.i(TAG, "Creating EthernetConfigStore");
mEthernetConfigStore = new EthernetConfigStore();
mIpConfiguration = mEthernetConfigStore.readIpAndProxyConfigurations();
Log.i(TAG, "Read stored IP configuration: " + mIpConfiguration);
mTracker = new EthernetNetworkFactory(mListeners); //創建本地的網絡工廠
mTracker.setContext(context); //add by peng
}
2、frameworks\opt\net\ethernet\java\com\android\server\ethernet\EthernetNetworkFactory
EthernetNetworkFactory(RemoteCallbackList<IEthernetServiceListener> listeners) {
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, "");
mLinkProperties = new LinkProperties();
initNetworkCapabilities(); //初始化網絡參數,比如,上下行速度、傳輸類型等
mListeners = listeners;
}
//我們看看這個類的start函數
public synchronized void start(Context context, Handler target) {
// The services we use.
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
mNMService = INetworkManagementService.Stub.asInterface(b);
mEthernetManager = (EthernetManager) context.getSystemService(Context.ETHERNET_SERVICE); //獲取服務
// Interface match regex.
mIfaceMatch = context.getResources().getString(
com.android.internal.R.string.config_ethernet_iface_regex);
// Create and register our NetworkFactory.
mFactory = new LocalNetworkFactory(NETWORK_TYPE, context, target.getLooper());
mFactory.setCapabilityFilter(mNetworkCapabilities); //設置網絡參數
**mFactory.setScoreFilter(-1);** // 這個就是設置網絡評分,但是這爲-1,因爲這是初始化,等有網卡接入,講評分拉高就行,後面會講述
mFactory.register();//註冊
//再來看看當網卡接入的時候做了什麼
private void updateInterfaceState(String iface, boolean up) {
if (!mIface.equals(iface)) {
return;
}
Log.d(TAG, "updateInterface: " + iface + " link " + (up ? "up" : "down"));
synchronized(this) {
mLinkUp = up;
mNetworkInfo.setIsAvailable(up);
if (!up) {
// Tell the agent we're disconnected. It will call disconnect().
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr);
sendEthernetStateChangedBroadcast(EthernetManager.ETHER_STATE_DISCONNECTED); //add by peng
}
updateAgent();//這個是更新數據的,來看看。
// set our score lower than any network could go
// so we get dropped. TODO - just unregister the factory
// when link goes down.
//這裏就是當發現網卡up的話就設置評分 否則將評分設置成-1.
mFactory.setScoreFilter(up ? NETWORK_SCORE : -1); //NETWORK_SCORE 就是自己定義的分數,我這裏假設定義70
}
}
//看看這個updateAgent();
public void updateAgent() {
synchronized (EthernetNetworkFactory.this) {
if (mNetworkAgent == null) return;
if (DBG) {
Log.i(TAG, "Updating mNetworkAgent with: " +
mNetworkCapabilities + ", " +
mNetworkInfo + ", " +
mLinkProperties);
}
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
mNetworkAgent.sendLinkProperties(mLinkProperties);
// never set the network score below 0.
mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0);//這個就是重點了,看看裏面做了什麼
}
}
3、在深入去看看sendNetworkScore(score)到底做了寫什麼。
public void sendNetworkScore(int score) {
if (score < 0) {
throw new IllegalArgumentException("Score must be >= 0");
}
queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, new Integer(score)); //很明顯是發送了一個消息 以及帶上了評分發送出去了
}
4、全局搜索了下,發現這個消息在ConnectivityService處理了。
case NetworkAgent.EVENT_NETWORK_SCORE_CHANGED: {
NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
if (nai == null) {
loge("EVENT_NETWORK_SCORE_CHANGED from unknown NetworkAgent");
break;
}
Integer score = (Integer) msg.obj;
if (score != null) updateNetworkScore(nai, score.intValue());
break;
}
private void updateNetworkScore(NetworkAgentInfo nai, int score) { //更新網絡評分
if (DBG) log("updateNetworkScore for " + nai.name() + " to " + score);
if (score < 0) {
loge("updateNetworkScore for " + nai.name() + " got a negative score (" + score +
"). Bumping score to min of 0");
score = 0;
}
final int oldScore = nai.getCurrentScore(); //獲取當前網絡評分,比如我之前連接的是WIFI,現在要連接以太網,看看這個函數。
nai.setCurrentScore(score);
rematchAllNetworksAndRequests(nai, oldScore);
sendUpdatedScoreToFactories(nai);
}
4、getCurrentScore();
private int getCurrentScore(boolean pretendValidated) {
int score = currentScore;
///M: Support for EPDG testing @{
if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_EPDG)) {
Log.d(TAG,"[peng add] Support for EPDG testing,this score --->"+score);
return score;
}
///@}
//add by peng , set ethernet priority highest.
if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) { //這個就是解決WIFI和以太網網絡評分的,先跳過。後面在來分析。
Log.d(TAG,"[peng add] Support for TRANSPORT_ETHERNET ,this score --->"+score);
return score;
}
if (!everValidated && !pretendValidated){
score -= UNVALIDATED_SCORE_PENALTY;
Log.d(TAG,"[peng add] everValidated and pretendValidated is false,this score --->"+score);
}
if (score < 0) score = 0;
if (networkMisc.explicitlySelected){
score = EXPLICITLY_SELECTED_NETWORK_SCORE; //從log看 WIFI的默認評分是60,隨着信號等級加強評分會增加,同時也會減,具體看WIFI的代碼吧!這裏無論是以太網還是WIFI都會走這個判斷,也就是WIFI和以太網的評分都走了100,那麼系統又怎麼選擇了打開誰呢?
Log.d(TAG,"[peng add] networkMisc.explicitlySelected,this score full--->"+score);
}
return score;
}
5、網絡切換,主要看ConnectivityService的rematchNetworkAndRequests方法。
…………
if (VDBG) {
log("currentScore = " +
(currentNetwork != null ? currentNetwork.getCurrentScore() : 0) +
", newScore = " + newNetwork.getCurrentScore());
}
if (currentNetwork == null ||
currentNetwork.getCurrentScore() <= newNetwork.getCurrentScore()) { //當連接的網絡評分小於或等於新的連接網絡評分,那麼就remove當前網絡,連接新的網絡。 也就可以分析出,只要是後者連的,優先級就最高。
if (currentNetwork != null) {
if (DBG) log(" accepting network in place of " + currentNetwork.name());
currentNetwork.networkRequests.remove(nri.request.requestId);
currentNetwork.networkLingered.add(nri.request);
affectedNetworks.add(currentNetwork);
} else {
if (DBG) log(" accepting network in place of null");
}
…………
6、如何設置以太網優先級最高?
將EthernetNetworkFactory的以太網評分增加
private static final int NETWORK_SCORE = 110; //大於100即可,因爲WIFI最大的評分是100
在NetworkAgentInfo的getCurrentScore方法裏添加以太網的評分,保證不被修改
//add by peng , set ethernet priority highest.
if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
Log.d(TAG,"[peng add] Support for TRANSPORT_ETHERNET ,this score --->"+score);
return score;
}
“`
這樣就可以避免WIFI和以太網同時連接了。具體問題具體分析,以上是個人觀點,如果解釋的不對,請多多包含。