分类: Android平台
2014-04-19 14:07:31
在Android系统中,不同类型的网络同时开启时,系统根据网络类型的优先级自动进行选择。
1. 网络优先级配置文件
frameworks/base/core/res/res/values/config.xml
与类NetworkConfig的成员变量一一对应,其中,第4个元素就是优先级设置值。
frameworks/base /core/java/android/net/ConnectivityManager.java中定义了网络类型:
public static
final int TYPE_MOBILE = 0;
public static final int TYPE_WIFI
= 1;
…..
public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI
frameworks/base/packages/SettingsProvider/res/values/defaults.xml
SystemServer启动 ConnectivityService服务,用户操作的类是 ConnectivityManager.java 通过aidl访问 ConnectivityService.java提供的服务。
frameworks/base /services/java/com/android/server/ConnectivityService.java
ConnectivityService的构造函数中读取使用网络优先级配置文件。 首先获取config.xml中的字符串保存在String数组naStrings 中,然后循环处理数组中的每个元素(如"wifi,1,1,1,-1,true")。声明一个NetworkConfig对象时把每个String元素作为参数,最后把每个NetworkConfig对象加到数组mNetConfigs中。至此,有关各种网络的配置都保存在数组mNetConfigs里。
网络在启动的时候,会发出一个message(EVENT_STATE_CHANGED),这个消息会在ConnectivityService的内部类NetworkStateTrackerHandler中被处理。
当网络启动时,最终会调用到函数handleConnect。
if (mNetConfigs[newNetType].isDefault()) {
if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != newNetType) {
if (isNewNetTypePreferredOverCurrentNetType(newNetType)) {
// tear down the other
NetworkStateTracker otherNet =
mNetTrackers[mActiveDefaultNetwork];
if (DBG) {
log("Policy requires " + otherNet.getNetworkInfo().getTypeName() + " teardown");
}
if (!teardown(otherNet)) {
loge("Network declined teardown request");
teardown(thisNet);
return;
}
} else {
// don't accept this one
if (VDBG) {
log("Not broadcasting CONNECT_ACTION " +
"to torn down network " + info.getTypeName());
}
teardown(thisNet);
return;
}
}
......
mActiveDefaultNetwork = newNetType;
第一个if是判断网络是不是默认路由的,上文提到的config.xml中wifi、Ethernet、mobile都是默认路由的。第二个if是根据变量mActiveDefaultNetwork 来判断是否有其他网络正在运行。如果有的话,就对两种网络的优先级进行比较。优先比较是通过函数isNewNetTypePreferredOverCurrentNetType来实现的。如果返回false则不连接网络并返回。如果返回true则断开当前网络,并把newNetType赋给mActiveDefaultNetwork,确保之后的网络操作使用的是新的网络连接。
分析函数isNewNetTypePreferredOverCurrentNetType:
private boolean isNewNetTypePreferredOverCurrentNetType(int type) {
if ((type != mNetworkPreference &&
mNetConfigs[mActiveDefaultNetwork].priority >
mNetConfigs[type].priority) ||
mNetworkPreference == mActiveDefaultNetwork) return false;
return true;
}
((新连接的网络类型 不 等于偏好) 且 (新连接网络类型优先级 低于 当前网络类型优先级))
或者 (偏好类型正是当前网络类型))
则不切
isNewNetTypePreferredOverCurrentNetType是判断是否切换为新启动的网络。从函数代码可以发现,变量mNetworkPreference 起到了很关键的作用,因为当mActiveDefaultNetwork等于mNetworkPreference时,不管优先级怎样,函数直接返回false。
通过查找,知道mNetworkPreference是在ConnectivityService的构造函数中初始化的。mNetworkPreference = getPersistedNetworkPreference();
private int getPersistedNetworkPreference() {
final ContentResolver cr = mContext.getContentResolver();
final int networkPrefSetting = Settings.Global
.getInt(cr, Settings.Global.NETWORK_PREFERENCE, -1);
if (networkPrefSetting != -1) {
return networkPrefSetting;
}
return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE;
}
第1、2句是获取ContentProvider与Settings.Global.NETWORK_PREFERENCE对应的值。该ContentProvider是在类DataBaseHelper中初始化,其中有一句关键的代码
db.execSQL("INSERT INTO system ('name', 'value') values ('network_preference', '" +
ConnectivityManager.DEFAULT_NETWORK_PREFERENCE + "')");可见其实保存的也是ConnectivityManager.DEFAULT_NETWORK_PREFERENCE的值,故mNetworkPreference = ConnectivityManager.DEFAULT_NETWORK_PREFERENCE。
在ConnectivityService中通过 public NetworkInfo getNetworkInfo(int networkType)方法可以得知当前networkType类型网络的连接情况。