Android网络切换分析
来源:互联网 发布:oracle数据库下载64位 编辑:程序博客网 时间:2024/05/22 02:30
在Android系统中,不同类型的网络同时开启时,系统总会自动选择一种网络。这是怎么实现的呢?我们不难想到,如果各种网络已经事先定义好了优先级,那么系统就能根据网络类型的优先级自动进行选择。下面将详细讲述:
1. 网络优先级配置文件
各种不同类型的网络是在文件config.xml中进行配置,config.xml的路径如下:\android\frameworks\base\core\res\res\values 其中网络配置的内容如下:
- <string-array translatable="false" name="networkAttributes">
- <item>"wifi,1,1,1,-1,true"</item>
- <item>"ethernet,9,9,0,-1,true"</item>
- <item>"mobile,0,0,0,-1,true"</item>
- <item>"mobile_mms,2,0,2,60000,true"</item>
- <item>"mobile_supl,3,0,2,60000,true"</item>
- <item>"mobile_hipri,5,0,3,60000,true"</item>
- <item>"mobile_fota,10,0,2,60000,true"</item>
- <item>"mobile_ims,11,0,2,60000,true"</item>
- <item>"mobile_cbs,12,0,2,60000,true"</item>
- <item>"wifi_p2p,13,1,0,-1,true"</item>
- </string-array>
上面各项字符串的排列顺序与类NetworkConfig的成员变量一一对应,按顺序如下:
name,type,radio,priority,restoreTime,dependencyMet
第4个元素就是我们需要的优先级设置值
2. ConnectivityService服务
在上面的内容中,我们在配置文件中设置了不同网络类型的优先级。那么配置文件里面的设置是在什么时候被系统读取使用的呢?通过查看源代码会发现是在类ConnectivityService的构造函数中被调用的。具体代码如下:
- String[] naStrings = context.getResources().getStringArray(
- com.android.internal.R.array.networkAttributes);
- for (String naString : naStrings) {
- try {
- NetworkConfig n = new NetworkConfig(naString);
- if (n.type > ConnectivityManager.MAX_NETWORK_TYPE) {
- loge("Error in networkAttributes - ignoring attempt to define type " +
- n.type);
- continue;
- }
- if (mNetConfigs[n.type] != null) {
- loge("Error in networkAttributes - ignoring attempt to redefine type " +
- n.type);
- continue;
- }
- if ((mRadioAttributes[n.radio] == null) && (n.type != ConnectivityManager.TYPE_ETHERNET)) {
- loge("Error in networkAttributes - ignoring attempt to use undefined " +
- "radio " + n.radio + " in network type " + n.type);
- continue;
- }
- mNetConfigs[n.type] = n;
- mNetworksDefined++;
- } catch(Exception e) {
- // ignore it - leave the entry null
- }
- }
首先获取config.xml中的字符串保存在String数组naStrings 中,然后循环处理数组中的每个元素(如"wifi,1,1,1,-1,true")。之前我们说过,每个元素中的各项跟类NetworkConfig的成员变量对应。这里的处理主要是在声明一个NetworkConfig对象时把每个String元素作为参数,最后把每个NetworkConfig对象加到数组mNetConfigs中。至此,有关各种网络的配置都保存在数组mNetConfigs里。接下来,看看mNetConfigs数组是在什么时候派上用场的?
通过阅读源代码,可以知道各种网络在启动的时候,会发出一个message(EVENT_STATE_CHANGED),这个消息会在ConnectivityService的内部类NetworkStateTrackerHandler中被处理。代码如下:
- private class NetworkStateTrackerHandler extends Handler {
- ......
- @Override
- public void handleMessage(Message msg) {
- NetworkInfo info;
- switch (msg.what) {
- case NetworkStateTracker.EVENT_STATE_CHANGED:
- ......
- if (info.getDetailedState() ==
- NetworkInfo.DetailedState.FAILED) {
- handleConnectionFailure(info);
- } else if (info.getDetailedState() ==
- DetailedState.CAPTIVE_PORTAL_CHECK) {
- handleCaptivePortalTrackerCheck(info);
- } else if (state == NetworkInfo.State.DISCONNECTED) {
- handleDisconnect(info);
- } else if (state == NetworkInfo.State.SUSPENDED) {
- handleDisconnect(info);
- } else if (state == NetworkInfo.State.CONNECTED) {
- handleConnect(info);
- }
- ......
当网络启动时,最终会调用到函数handleConnect,下面看看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的值到底是什么?
通过查找,知道mNetworkPreference是在ConnectivityService的构造函数中初始化的。
mNetworkPreference = getPersistedNetworkPreference();
下面看一下函数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
3 网络相关的svc命令
上面我们提到的变量mNetworkPreference除了在初始化的时候会改变它的值,还有一个函数也能改变它的值。这个函数是ConnectivityService中的setNetworkPreference。查看源代码可以发现,DataCommand和WifiCommand都调用了ConnectivityService中的这个函数。而DataCommand和WifiCommand是在Svc中初始化的。看到这里,大概可以猜到通过Android的svc命令能够实现上述两个类定义的功能。其中,DataCommand实现对移动网络的开启、关闭和优先选择设置,WifiCommand实现对wifi网络的开启、关闭和优先选择设置。下面看一下命令svc的使用方法:
- # svc data
- svc data
- Control mobile data connectivity
- usage: svc data [enable|disable]
- Turn mobile data on or off.
- //设置移动网络的数据是否启用
- svc data prefer
- Set mobile as the preferred data network
- //设置移动网络的数据优先于WIFI
- # svc wifi
- svc wifi
- Control the Wi-Fi manager
- usage: svc wifi [enable|disable]
- Turn Wi-Fi on or off.//设置WIFI是否启用
- svc wifi prefer
- Set Wi-Fi as the preferred data network //设置WIFI优先于移动网络的数据,一般应设置成这样,除非你刻意使用移动网络数据传输
svc data prefer最终会改变mNetworkPreference的值。
- Android网络切换分析
- Android网络切换分析
- Android网络切换分析
- Android 网络切换
- android网络切换问题
- Android监听网络切换
- android 语言切换分析
- Android网络切换状态广播
- Android5.1网络切换策略分析
- android 语言切换过程分析
- Android -- 网络管理分析
- Android -- 网络管理分析
- Android -- 网络管理分析
- Android -- 网络管理分析
- Android -- 网络管理分析
- Android -- 网络管理分析
- Android APN设置之切换网络
- Android 开发:APN网络切换之CMNET
- 问问你为何还没有等到
- PM的自我修养——微信5.0 for Android 设计思路(二)
- XVID解码器不弹出status窗口的办法
- jQuery 选择器
- 移动发送短信接口测试
- Android网络切换分析
- xcode 制作静态库.a文件 详解
- SQL基础学习
- Directshow视频采集保存
- 强制SQL SERVER使用某种表连接方式
- RMI网络编程开发之一 JAVA“进程间”通信方式
- treeview 选中,移动,重命名
- 判断一个正整数是否为质数的算法
- 三种方法求最大连续子数组的和