from:http://blog.youkuaiyun.com/u013686019/article/details/51447129
Android版本:
- Android 4.4.4
涉及内容:
- 1,网络优先级;
- 2,网络切换;
- 3,界面显示。
解决问题:
- 1,更改网络优先级:让以太网(eth0)优先级高于WiFi(Wlan0);
- 2,WiFi切换到以太网异常原因及解决。
一、
网络优先级
1、
Android支持的网络类型
Android系统framework层的ConnectivityManager.java文件中
定义了支持的所有网络类型:
- 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 TYPE_MOBILE_MMS = 2;
- public static final int TYPE_MOBILE_SUPL = 3;
- public static final int TYPE_MOBILE_DUN = 4;
- public static final int TYPE_MOBILE_HIPRI = 5;
- public static final int TYPE_WIMAX = 6;
- public static final int TYPE_BLUETOOTH = 7;
- public static final int TYPE_DUMMY = 8;
- public static final int TYPE_ETHERNET = 9;
- public static final int TYPE_MOBILE_FOTA = 10;
- public static final int TYPE_MOBILE_IMS = 11;
- public static final int TYPE_MOBILE_CBS = 12;
- public static final int TYPE_WIFI_P2P = 13;
对于上网,接触的几乎都是
TYPE_WIFI、
TYPE_MOBILE、TYPE_ETHERNET这三种。
这些网络的优先级定义在config.xml文件的networkAttributes数组
中:
- frameworks\base\core\res\res\values\config.xml
- <!-- This string array should be overridden by the device to present a list of network attributes, based on the hardware -->
- <string-array translatable="false" name="networkAttributes">
- <item>"wifi,1,1,1,-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>
- <item>"mobile_ia,14,0,2,-1,true"</item>
- <item>"bluetooth,7,7,1,60000,true"</item>
- <item>"eth,9,9,4,60000,true"</item>
- </string-array>
注意
networkAttributes数组前的注释!
大意是说,对某种网络支持与否取决与硬件,所以该文件会被源码目录/device/下的config.xml定义的
networkAttributes数组覆盖!!!
也就是说,真正起作用的优先级配置在
源码目录/device/
下的config.xml中定义。
对于
networkAttributes数组的每一个item:
- <item>"wifi,1,1,1,-1,true"</item>
- frameworks\base\core\java\android\net\NetworkConfig.java
- public class NetworkConfig {
- /**
- * Human readable string
- */
- public String name;
- /**
- * Type from ConnectivityManager
- */
- public int type;
- /**
- * the radio number from radio attributes config
- */
- public int radio;
- /**
- * higher number == higher priority when turning off connections
- */
- public int priority;
- /**
- * indicates the boot time dependencyMet setting
- */
- public boolean dependencyMet;
- /**
- * indicates the default restoral timer in seconds
- * if the network is used as a special network feature
- * -1 indicates no restoration of default
- */
- public int restoreTime;
- /**
- * input string from config.xml resource. Uses the form:
- * [Connection name],[ConnectivityManager connection type],
- * [associated radio-type],[priority],[dependencyMet]
- */
- public NetworkConfig(String init) {
- String fragments[] = init.split(",");
- name = fragments[0].trim().toLowerCase(Locale.ROOT);
- type = Integer.parseInt(fragments[1]);
- radio = Integer.parseInt(fragments[2]);
- priority = Integer.parseInt(fragments[3]);
- restoreTime = Integer.parseInt(fragments[4]);
- dependencyMet = Boolean.parseBoolean(fragments[5]);
- }
- }
2、更改以太网优先级高于WiFi
- <item>"eth,9,9,0,60000,true"</item>
- frameworks\base\services\java\com\android\server\ConnectivityService.java
- mNetworkPreference = getPersistedNetworkPreference();
- private int getPersistedNetworkPreference() {
- final ContentResolver cr = mContext.getContentResolver();
- // 设置Preferred网络为TYPE_ETHERNET
- Settings.Global.putInt(cr, Settings.Global.NETWORK_PREFERENCE, ConnectivityManager.TYPE_ETHERNET);
- final int networkPrefSetting = Settings.Global
- .getInt(cr, Settings.Global.NETWORK_PREFERENCE, -1);
- log("networkPrefSetting: " + networkPrefSetting);
- if (networkPrefSetting != -1) {
- return networkPrefSetting;
- }
- return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE;
- }
3、网络优先级的读取
- frameworks\base\services\java\com\android\server\ConnectivityService.java
- public ConnectivityService() {
- if (DBG) log("ConnectivityService starting up");
- boolean wifiOnly = SystemProperties.getBoolean("ro.radio.noril", false);
- log("wifiOnly=" + wifiOnly);
- String[] naStrings = context.getResources().getStringArray(com.android.internal.R.array.networkAttributes);
- for (String naString : naStrings) {
- try {
- NetworkConfig n = new NetworkConfig(naString);
- if (VDBG) log("naString=" + naString + " config=" + n);
- mNetConfigs[n.type] = n;
- mNetworksDefined++;
- }
- }
- }
Log如下:
二、
网络切换
现在,优先级:Ethernet > WiFi,在WiFi连接的情况下,点击【使用以太网】按钮进行网络切换:
先响应一个EVENT_CONFIGURATION_CHANGED事件:
- frameworks\base\services\java\com\android\server\ConnectivityService.java
- case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: {
- info = (NetworkInfo) msg.obj;
- handleConnectivityChange(info.getType(), false);
- break;
- }
对网络是否切换的仲裁在 handleConnect()方法中调用的 isNewNetTypePreferredOverCurrentNetType()方法:
- frameworks\base\services\java\com\android\server\ConnectivityService.java
- private void handleConnect(NetworkInfo info) {
- final int newNetType = info.getType();
- if (VDBG) {
- log("handleConnect: E newNetType=" + newNetType + " thisIface=" + thisIface
- + " isFailover" + isFailover);
- }
- // if this is a default net and other default is running
- // kill the one not preferred
- 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;
- }
- }
- }
- }
- private boolean isNewNetTypePreferredOverCurrentNetType(int type) {
- log("type = "+ type);
- log("mNetworkPreference = " + mNetworkPreference);
- log("mActiveDefaultNetwork = " + mActiveDefaultNetwork);
- log("mNetConfigs[mActiveDefaultNetwork].priority = " + mNetConfigs[mActiveDefaultNetwork].priority);
- log("mNetConfigs[type].priority = " + mNetConfigs[type].priority);
- if (((type != mNetworkPreference)
- && (mNetConfigs[mActiveDefaultNetwork].priority > mNetConfigs[type].priority))
- || (mNetworkPreference == mActiveDefaultNetwork)) {
- log("return false");
- return false;
- }
- log("return true");
- return true;
- }
mNetworkPreference = 9,之前设置的Preferred网络。
mActiveDefaultNetwork = 1,当前使用的网络,即WiFi。
经过
isNewNetTypePreferredOverCurrentNetType()的仲裁,返回true进行网络切换:
广播发送地:
IsWiFiConnected()运行先于WiFi的teardown(),所以在teardown()更改WiFi的状态是无效的。。。既然现在需要Ethernet优先级高于WiFi,直接让IsWiFiConnected()返回false即可。
- Policy requires WIFI teardown
至此,
Ethernet当道,WiFi让行。
三、界面显示
在【Settings-->以太网】界面,【使用以太网】选项一直处于连接状态且不可点击,IP地址等信息亦不见;此时进入Shell用ifconfig查看IP,
可知以太网IP等已经获取、且WiFi已经断掉、且ping网络正常。
原因去在Settings部分查找:
- packages\apps\settings\src\com\android\settings\ethernet\EthernetSettings.java
- public void getEthInfo(int state){
- if (state == EthernetDataTracker.ETHER_STATE_CONNECTING) {
- mUseEthernet.setEnabled(false);
- mUseEthernet.setSummary(R.string.ethernet_connecting);
- clearIpInfo();
- } else if (state == EthernetDataTracker.ETHER_STATE_DISCONNECTED) {
- mUseEthernet.setEnabled(true);
- mUseEthernet.setSummary(R.string.ethernet_unconnected);
- clearIpInfo();
- } else if (state == EthernetDataTracker.ETHER_STATE_CONNECTED) {
- mUseEthernet.setEnabled(true);
- mUseEthernet.setSummary(R.string.ethernet_connected);
- if(isUsingStaticIp()) {
- getEthInfoFromStaticIP();
- } else {
- getEthInfoFromDhcp();
- }
- mEthmac = getEthMac();
- }
- }
mUseEthernet不可用原因是以太网一
直处于
ETHER_STATE_CONNECTING
状态,以太网状态来自:
- packages\apps\settings\src\com\android\settings\ethernet\EthernetSettings.java
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- int state = intent.getIntExtra(EthernetDataTracker.EXTRA_ETHERNET_STATE, 0);
- Log.d(TAG, "BroadcastReceiver: Ethernet current state:" + state);
- getEthInfo(state);
- }
- };
广播发送地:
- frameworks\base\core\java\android\net\EthernetDataTracker.java
- private void runDhcp() {
- Log.d(TAG, "mIface = " + mIface + ", isEthernetEnabled() = " + isEthernetEnabled());
- if(!mIface.isEmpty() && isEthernetEnabled()) {
- registerEthernetContentObserver(); // register here when boot with plugged ethernet
- {
- // send connected msg only when wifi disconnect
- if(!IsWiFiConnected()) {
- sendEthStateChangedBroadcast(ETHER_STATE_CONNECTED);
- } else {
- Log.e(TAG, "WiFiConnected, cannot send ETHER_STATE_CONNECTED MSG");
- }
- }
- }
- }
- private Boolean IsWiFiConnected() {
- try {
- ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- boolean isWiFiConnected = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnected();
- Log.e(TAG, "isWiFiConnected: " + isWiFiConnected);
- return isWiFiConnected;
- }
- }
可知:虽然
WiFi已经被teardown,但IsWiFiConnected()依旧返回true,即WiFi状态没被更新:
- frameworks\base\wifi\java\android\net\wifi\WifiStateTracker.java
- public boolean teardown() {
- mTeardownRequested.set(true);
- mWifiManager.stopWifi();
- return true;
- }