浅谈Android的ConnectivityService网络连接服务

打印 上一主题 下一主题

主题 977|帖子 977|积分 2931

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x


目次

1、概述
2、原理
3、网络工厂
4、网络类型注册
5、网络链接哀求
6、网络评分机制
总结
8、附表
表1:代码路径
表2:网络能力
表3:网络透传能力
9、扩展:怎样举行第二路拨号并访问网络
9.1 拨号
9.2 访问




1、概述

ConnectivityService在 Android 系统中是一个核心的服务,它主要负责管理和监控网络连接的状态。这个服务是 Android 框架的一部分,为应用程序和系统服务提供了关于网络连接(如 wifi、mobile network、ethernet、bt-pan)的详细信息。

ConnectivityService作为管理员身份,每种网络都会去向它注册,网络的利用权全靠它来分配。并实现了网络评分机制确保了系统能够最出作优的网络连接,从而为用户提供更好的网络体验。

2、原理


相干类的功能说明如下:


  • ConnectivityService是个服务,用来管理网络链接。
  • ConnectivityManager是ConnectivityService的署理,署理意思是调用者不要关心具体接口的实现,只管调用,以是才设计此模式。以是ConnectivityManager作用是对外提供ConnectivityService的相干接口。
  • TelephonyNetworkFatory是个移动的网络工厂,父类是NetworkFactory,用于SIM卡业务的数据链接。
  • WifiNetworkFatory是个Wifi的网络工厂,父类是NetworkFactory,用于WIFI模块的数据链接。
  • EthernetNetworkFatory是个以太网的网络工厂,父类是NetworkFactory,用于以太网业务的数据链接。

ConnectivityService链接服务从箭头来看分为2个流程,分别为注册和网络选择。


  • 注册:见红色箭头,在设备开机时,相干的网络工厂会向ConnectivityService举行注册register,ConnectivityManager是个署理,ConnectivityService对外提供的接口都由ConnectivityManager提供,末了在register函数里通过调用registerNetworkProvider,ConnectivityService就拿到了各种类型的网络工厂,比如移动,Wifi,以太网等。
  • 网络选择:见绿色箭头,假如存在多种网络的情况下,ConnectivityService根据evalRequest逻辑举行评分,分数高的网络工厂会优先利用,这叫做网络评分机制。从流程图可以看出,当应用调用哀求网络requestNetwork时(此函数是发起一个网络链接哀求),最终根据evalRequest函数找到分数最高的网络工厂然后调用它的needNetworkFor来完成网络链接哀求。
3、网络工厂

NetworkFactory网络工厂其实是通过工厂模式天生各自特有功能的网络类型。

上图的圆圈是网络工厂的相干类图,TelephonyNetworkFatory、WifiNetworkFatory、EthernetNetworkFatory网络类型继承NetworkFatory,NetworkFatory的重点override接口如下:


  • needNetworkFor:哀求网络链接接口
  • releaseNetworkFor:释放网络链接接口
  • setScoreFilter(int score): 设置分数,除了初始评分外,各个网络的评分还会根据实时状态举行调解。
比方,以太网会根据网卡的up和down状态,把分值设置为70(当网卡up时)或0(当网卡down时)。Wi-Fi的分值还跟信号状态、当前数据速率等一系列因素有关,在WifiStateMachine.java的calculateWifiScore函数中举行盘算,初始盘算的基础分值为56,然后根据wifi网络的状态举行小的加减,末了假如分值大于60,就把分值设置为60。


  • register(): 向ConnectivityService注册,这样ConnectivityService就能拿到各类型的网络。用于后面选择评分高的网络举行链接。
NetworkProvider直译是网络提供者,和对应的网络工厂绑定,用于告知ConnectivityService,方便异步调用网络提供者。
4、网络类型注册


在开机时,各网络类型通过调用register向ConnectivityService举行注册,函数代码如下:
  1. 1.        public void register() {  
  2. 2.            if (mProvider != null) {  
  3. 3.                throw new IllegalStateException("A NetworkFactory must only be registered once");  
  4. 4.            }  
  5. 5.            if (DBG) log("Registering NetworkFactory");  
  6. 6.          
  7. 7.            mProvider = new NetworkProvider(mContext, NetworkFactory.this.getLooper(), LOG_TAG) {  
  8. 8.                @Override  
  9. 9.                public void onNetworkRequested(@NonNull NetworkRequest request, int score,  
  10. 10.                        int servingProviderId) {  
  11. 11.                    handleAddRequest(request, score, servingProviderId);  
  12. 12.                }  
  13. 13.          
  14. 14.                @Override  
  15. 15.                public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) {  
  16. 16.                    handleRemoveRequest(request);  
  17. 17.                }  
  18. 18.            };  
  19. 19.          
  20. 20.            ((ConnectivityManager) mContext.getSystemService(  
  21. 21.                Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider);  
  22. 22.        }  
复制代码
从如上代码可以看出,先创建一个NetworkProvider的对象mProvider,此对象之前说过,方便ConnectivityService举行异步调用,也就是NetworkProvider有相干的Messenger实现。
末了调用ConnectivityService的registerNetworkProvider函数完成注册,把NetworkProvider放到mNetworkProviderInfos这个成员数组里。其实ConnectivityService最终拿到的是NetworkFactory的NetworkProvider相干接口。
5、网络链接哀求


应用层怎样发起网络链接哀求,本文以TelephonyNetworkFatory为例说明。
ConnectivityManager对外提供了一个requestNetwork接口,以是应用层调用此接口即可。
  1. 1.        NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();  
  2. 2.        networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);  
  3. 3.        networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);  
  4. 4.        // During an emergency call, and when we have cached the Active Sub Id, we set the  
  5. 5.        // Network Specifier so that the network request goes to the correct Sub Id  
  6. 6.        if (mNiHandler.getInEmergency() && mActiveSubId >= 0) {  
  7. 7.            if (DEBUG) Log.d(TAG, "Adding Network Specifier: " + Integer.toString(mActiveSubId));  
  8. 8.            networkRequestBuilder.setNetworkSpecifier(Integer.toString(mActiveSubId));  
  9. 9.        }  
  10. 10.        NetworkRequest networkRequest = networkRequestBuilder.build();  
  11. 11.        mConnMgr.requestNetwork(
  12. 12.                networkRequest,  
  13. 13.                mSuplConnectivityCallback,  
  14. 14.                mHandler,  
  15. 15.                SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS);  
复制代码
requestNetwork函数有2个重要的参数:

  • NetworkRequest:网络哀求封装,如通过什么能力及什么方式透传。
addCapability:通过此函数设置网络能力,见表2。它用于向网络哀求添加特定的网络能力,具体来说,addCapability用于指定一个网络哀求所需或支持的网络特性,跟APN有关。本示例的网络能力是安全用户平面定位(SUPL),用于GPS辅助定位服务。
addTransportType:函数用于指定网络连接所利用的传输类型,见表3。传输类型决定了网络哀求所利用的底层传输技能,比方Wi-Fi、蜂窝数据等。本示例的传输类型是移动网络。

  • NetworkCallback:网络哀求的回调,具体是ConnectivityManager.NetworkCallback,回调的接口有onAvailable,onLost,onUnavailable。
关于requestNetwork接下来怎样调用,请参考时序图,这里不再讲解。
6、网络评分机制

  触发网络评分机制有很多多少种方法,如修改分数,下发网络哀求等。这些最终都会触发evalRequest函数的调用,代码如下:
  1. 1.        private void evalRequest(NetworkRequestInfo n) {  
  2. 2.            if (VDBG) {  
  3. 3.                log("evalRequest");  
  4. 4.                log(" n.requests = " + n.requested);  
  5. 5.                log(" n.score = " + n.score);  
  6. 6.                log(" mScore = " + mScore);  
  7. 7.                log(" request.providerId = " + n.providerId);  
  8. 8.                log(" mProvider.id = " + mProvider.getProviderId());  
  9. 9.            }  
  10. 10.            if (shouldNeedNetworkFor(n)) {  
  11. 11.                if (VDBG) log("  needNetworkFor");  
  12. 12.                needNetworkFor(n.request, n.score);  
  13. 13.                n.requested = true;  
  14. 14.            } else if (shouldReleaseNetworkFor(n)) {  
  15. 15.                if (VDBG) log("  releaseNetworkFor");  
  16. 16.                releaseNetworkFor(n.request);  
  17. 17.                n.requested = false;  
  18. 18.            } else {  
  19. 19.                if (VDBG) log("  done");  
  20. 20.            }  21.        }
复制代码
shouldNeedNetworkFor函数用于确认是否举行网络链接哀求,shouldReleaseNetworkFor函数用于释放网络链接哀求。
shouldNeedNetworkFor的函数代码如下,具体逻辑是:假如NetworkRequestInfo没有被requested过,而且其分值(n.score)小于当前NetworkFactory自己的分值(mScore),那么就说明,当前NetworkFactory所处的网络优先级高于其他网络的优先级,就会触发当前NetworkFactory所在网络的needNetworkFor()流程,也就是连接创建流程,并将标志NetworkRequestInfo.requested=true。当NetworkRequestInfo被requested过(也就是当前网络被needNetworkFor过),此时假如再次收到哀求,而且携带的新score大于当前NetworkFactory所处网络的mScore,那么就说明当前NetworkFactory所在网络优先级已经不是最高,需要将其releaseNetworkFor掉,并标志NetworkRequestInfo.requested=false。
  1. 1.        private boolean shouldNeedNetworkFor(NetworkRequestInfo n) {  
  2. 2.                // If this request is already tracked, it doesn't qualify for need  
  3. 3.                return !n.requested  
  4. 4.                    // If the score of this request is higher or equal to that of this factory and some  
  5. 5.                    // other factory is responsible for it, then this factory should not track the request  
  6. 6.                    // because it has no hope of satisfying it.  
  7. 7.                    && (n.score < mScore || n.providerId == mProvider.getProviderId())  
  8. 8.                    // If this factory can't satisfy the capability needs of this request, then it  
  9. 9.                    // should not be tracked.  
  10. 10.                    && n.request.canBeSatisfiedBy(mCapabilityFilter)  
  11. 11.                    // Finally if the concrete implementation of the factory rejects the request, then  
  12. 12.                    // don't track it.  
  13. 13.                    && acceptRequest(n.request, n.score);  
  14. 14.            }  
复制代码
总结

  本文大概讲了ConnectivityService框架及接口利用说明,涉及的还不是很深。后面有问题再具体总结分析这块的内容。
8、附表

表1:代码路径

路径
frameworks\opt\telephony\src\java\com\android\internal\telephony\dataconnection\TelephonyNetworkFactory.java
frameworks\libs\net\common\src_servicescommon\android\net\NetworkFactory.java
frameworks\base\core\java\android\net\NetworkCapabilities.java
frameworks\base\core\java\android\net\NetworkRequest.java
frameworks\base\core\java\android\net\ConnectivityManager.java
frameworks\base\core\java\android\net\ Network.java
frameworks\base\core\java\android\net\ NetworkProvider.java
frameworks\base\services\core\java\com\android\server\ConnectivityService.java
frameworks\opt\net\ethernet\java\com\android\server\ethernet\ EthernetNetworkFactory.java
表2:网络能力

NetworkCapabilities

ApnSetting

能力说明

NET_CAPABILITY_MMS

TYPE_MMS

多媒体消息服务(MMS),用于发送和接收彩信。

NET_CAPABILITY_SUPL

TYPE_SUPL

安全用户平面定位(SUPL),用于GPS辅助定位服务。

NET_CAPABILITY_DUN

TYPE_DUN

拨号上网(DUN),允许设备通过移动网络为其他设备提供网络连接。

NET_CAPABILITY_FOTA

TYPE_FOTA

固件空中升级(FOTA),允许设备通过移动网络接收固件更新。

NET_CAPABILITY_IMS

TYPE_IMS

IP多媒体子系统(IMS),用于支持VoIP等多媒体通信服务。

NET_CAPABILITY_CBS

TYPE_CBS

小区广播服务(CBS),用于向手机用户发送小区内的短消息。

NET_CAPABILITY_IA

TYPE_IA

这个名称不太常见,大概表示某种特定类型的网络访问或功能。

NET_CAPABILITY_EIMS

TYPE_EMERGENCY

紧急IMS,大概用于紧急情况下的多媒体通信。

NET_CAPABILITY_INTERNET

TYPE_DEFAULT

表示网络可以访问互联网。

NET_CAPABILITY_WIFI_P2P


Wi-Fi直连(P2P),允许设备之间直接通过Wi-Fi举行通信,无需接入点。

NET_CAPABILITY_RCS


丰富的呼唤服务(RCS),用于增强语音呼唤的功能,如视频通话、即时消息等。

NET_CAPABILITY_XCAP


XML设置访问协议(XCAP),一种用于存储和检索XML文档的协议。

NET_CAPABILITY_NOT_METERED


表示网络流量不计费。

NET_CAPABILITY_NOT_RESTRICTED


表示网络没有访问限制。

NET_CAPABILITY_TRUSTED


表示网络是可信的。

表3:网络透传能力

TransportType
能力名称
能力说明
TRANSPORT_CELLULAR:
蜂窝数据网络
如2G、3G、4G(LTE)、5G等移动网络。
TRANSPORT_WIFI
Wi-Fi网络

通过无线局域网连接到互联网。
TRANSPORT_BLUETOOTH
蓝牙网络
固然蓝牙通常不消于互联网连接,但在某些特定场景下(如蓝牙PAN)大概用作数据传输。
TRANSPORT_ETHERNET
以太网网络
这通常指的是有线网络连接,但在Android设备上较为稀有,因为移动设备主要利用无线连接。
TRANSPORT_VPN
捏造私人网络(VPN)
这是一种通过公共网络(如互联网)创建加密通道的技能,用于在远程服务器上安全地发送和接收数据。
9、扩展:怎样举行第二路拨号并访问网络

9.1 拨号

在利用移动网络举行第二跑拨号时,要注意不能与当前的apn雷同,比如当前是default的apn,那么第二路只能利用其他apn类型拨号了,否则会报如下错误。
ConnectivityService: NetReassign [53 : null → 100]
利用APN为mms的拨号示例代码如下:
  1. 1.        import android.net.ConnectivityManager;
  2. 2.        import android.net.Network;
  3. 3.        import android.net.NetworkCapabilities;
  4. 4.        import android.net.NetworkInfo;
  5. 5.        import android.net.NetworkRequest;
  6. 6.       
  7. 7.        private ConnectivityManager.NetworkCallback createConnectivityCallback(){  
  8. 8.            return new ConnectivityManager.NetworkCallback() {  
  9. 9.                @Override  
  10. 10.                public void onAvailable(Network network) {  
  11. 11.                    // Specific to a change to a SUPL enabled network becoming ready  
  12. 12.                    Log.d(LOG_TAG, "test network connection available.");  
  13. 13.                }  
  14. 14.          
  15. 15.                @Override  
  16. 16.                public void onLost(Network network) {  
  17. 17.                    Log.d(LOG_TAG, "test network connection lost.");  
  18. 18.                }  
  19. 19.          
  20. 20.                @Override  
  21. 21.                public void onUnavailable() {  
  22. 22.                    Log.d(LOG_TAG, "test network connection request timed out.");  
  23. 23.                    // Could not setup the connection to the network in the specified time duration.  
  24. 24.          
  25. 25.                }  
  26. 26.            };  
  27. 27.        }  
  28. 28.        //发起移动网络拨号
  29. 29.        private void startSecDataCall()  
  30. 30.        {  
  31. 31.            ConnectivityManager mTConnMgr;  
  32. 32.            ConnectivityManager.NetworkCallback mConnectivityCallback = createConnectivityCallback();  
  33. 33.            mTConnMgr = (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);  
  34. 34.             
  35. 35.            NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();  
  36. 36.            networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);  
  37. 37.            networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);  
  38. 38.          
  39. 39.            NetworkRequest networkRequest = networkRequestBuilder.build();  
  40. 40.            mTConnMgr.requestNetwork(  
  41. 41.                    networkRequest,  
  42. 42.                    mConnectivityCallback,  
  43. 43.                    20 * 1000);  
  44. 44.        }  
复制代码

拨号成功后,可利用ifconfig指令查询网卡有没有辨认出来。

9.2 访问

利用第二路访问网络代码:
  1. 1.        import java.net.URL;  
  2. 2.        import java.net.MalformedURLException;  
  3. 3.        import java.io.IOException;  
  4. 4.        import java.net.URLConnection;  
  5. 5.        import java.io.ByteArrayOutputStream;  
  6. 6.          
  7. 7.        private String getTest(URLConnection urlConnection) throws IOException {  
  8. 8.                //URL url = new URL(pacUri.toString());  
  9. 9.                //URLConnection urlConnection = url.openConnection(java.net.Proxy.NO_PROXY);  
  10. 10.                long MAX_PAC_SIZE = 20 * 1000 * 1000;  
  11. 11.                long contentLength = -1;  
  12. 12.                try {  
  13. 13.                    contentLength = Long.parseLong(urlConnection.getHeaderField("Content-Length"));  
  14. 14.                } catch (NumberFormatException e) {  
  15. 15.                    // Ignore  
  16. 16.                }  
  17. 17.                if (contentLength > MAX_PAC_SIZE) {  
  18. 18.                    throw new IOException("PAC too big: " + contentLength + " bytes");  
  19. 19.                }  
  20. 20.                ByteArrayOutputStream bytes = new ByteArrayOutputStream();  
  21. 21.                byte[] buffer = new byte[1024];  
  22. 22.                int count;  
  23. 23.                while ((count = urlConnection.getInputStream().read(buffer)) != -1) {  
  24. 24.                    bytes.write(buffer, 0, count);  
  25. 25.                    if (bytes.size() > MAX_PAC_SIZE) {  
  26. 26.                        throw new IOException("PAC too big");  
  27. 27.                    }  
  28. 28.                }  
  29. 29.                Log.d(LOG_TAG, "bytes.size() = " + bytes.size());  
  30. 30.                return bytes.toString();  
  31. 31.            }  
  32. 32.          
  33. 33.        private ConnectivityManager.NetworkCallback createConnectivityCallback(){  
  34. 34.                return new ConnectivityManager.NetworkCallback() {  
  35. 35.                    @Override  
  36. 36.                    public void onAvailable(Network network) {  
  37. 37.                        // Specific to a change to a SUPL enabled network becoming ready  
  38. 38.                        Log.d(LOG_TAG, "test network connection available");  
  39. 39.                        URL mUrl;  
  40. 40.          
  41. 41.                        try {  
  42. 42.                            mUrl = new URL("https://www.baidu.com/");  
  43. 43.                            //Log.d(LOG_TAG, "test network mUrl = ", mUrl);  
  44. 44.                            getTest(network.openConnection(mUrl));  
  45. 45.                        } catch (IOException e) {  
  46. 46.                            //throw new MalformedURLException("open()", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);  
  47. 47.                            Log.d(LOG_TAG, "test network 11");  
  48. 48.                        }            
  49. 49.                    }  
  50. 50.          
  51. 51.                    @Override  
  52. 52.                    public void onLost(Network network) {  
  53. 53.                        Log.d(LOG_TAG, "test network connection lost.");  
  54. 54.                    }  
  55. 55.          
  56. 56.                    @Override  
  57. 57.                    public void onUnavailable() {  
  58. 58.                        Log.d(LOG_TAG, "test network connection request timed out.");  
  59. 59.                        // Could not setup the connection to the network in the specified time duration.  
  60. 60.          
  61. 61.                    }  
  62. 62.                };  
  63. 63.            }  
复制代码

可通过检察对应网卡的RX TX属性,确认是否从该网卡收发,见如下图。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

灌篮少年

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表