最近在在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 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和以太网同时连接了。具体问题具体分析,以上是个人观点,如果解释的不对,请多多包含。