[java] view plain copy PRint?Android 4.4.4 涉及内容:[html]%20view%20plain%20copy%20print?1,网络优先级; 2,网络切换; 3,界面显示。 解决问题:[html]%20view%20plain%20copy%20print?1,更改网络优先级:让以太网(eth0)优先级高于WiFi(Wlan0); 2,WiFi切换到以太网异常原因及解决。 一、网络优先级1、Android支持的网络类型Android系统framework层的ConnectivityManager.java文件中定义了支持的所有网络类型:[java]%20view%20plain%20copy%20print?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数组中:[html]%20view%20plain%20copy%20print?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:[html]%20view%20plain%20copy%20print?<item>"wifi,1,1,1,-1,true"</item> 其含义由NetworkConfig.java描述(一一对应):[html]%20view%20plain%20copy%20print?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[html]%20view%20plain%20copy%20print?<item>"eth,9,9,0,60000,true"</item> 并设置Preferred网络为以太网:[html]%20view%20plain%20copy%20print?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、网络优先级的读取[html]%20view%20plain%20copy%20print?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事件:[html] view plain copy print?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()方法:[html]%20view%20plain%20copy%20print?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%20=%209,之前设置的Preferred网络。mActiveDefaultNetwork%20=%201,当前使用的网络,即WiFi。经过isNewNetTypePreferredOverCurrentNetType()的仲裁,返回true进行网络切换:[html]%20view%20plain%20copy%20print?Policy requires WIFI teardown 至此,Ethernet当道,WiFi让行。三、界面显示在【Settings-->以太网】界面,【使用以太网】选项一直处于连接状态且不可点击,IP地址等信息亦不见;此时进入Shell用ifconfig查看IP,可知以太网IP等已经获取、且WiFi已经断掉、且ping网络正常。原因去在Settings部分查找:[java] view plain copy print?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状态,以太网状态来自:[java]%20view%20plain%20copy%20print?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); } }; 广播发送地:[java]%20view%20plain%20copy%20print?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状态没被更新:[java]%20view%20plain%20copy%20print?frameworks/base/wifi/java/android/net/wifi/WifiStateTracker.java public boolean teardown() { mTeardownRequested.set(true); mWifiManager.stopWifi(); return true; } IsWiFiConnected()运行先于WiFi的teardown(),所以在teardown()更改WiFi的状态是无效的。。。既然现在需要Ethernet优先级高于WiFi,直接让IsWiFiConnected()返回false即可。