灌篮少年 发表于 2024-8-24 06:59:40

浅谈Android的ConnectivityService网络连接服务



目次

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、原理

https://img-blog.csdnimg.cn/direct/563b0759295f4008aad124ef9d60ce7c.png
相干类的功能说明如下:


[*]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网络工厂其实是通过工厂模式天生各自特有功能的网络类型。
https://img-blog.csdnimg.cn/direct/ac84771c81504c52a61ce95cd5e84f70.png
上图的圆圈是网络工厂的相干类图,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、网络类型注册

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

https://img-blog.csdnimg.cn/direct/37f959897db24c82a15d6b310c00b458.png
应用层怎样发起网络链接哀求,本文以TelephonyNetworkFatory为例说明。
ConnectivityManager对外提供了一个requestNetwork接口,以是应用层调用此接口即可。
1.        NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
2.        networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
3.        networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
4.        // During an emergency call, and when we have cached the Active Sub Id, we set the
5.        // Network Specifier so that the network request goes to the correct Sub Id
6.        if (mNiHandler.getInEmergency() && mActiveSubId >= 0) {
7.          if (DEBUG) Log.d(TAG, "Adding Network Specifier: " + Integer.toString(mActiveSubId));
8.          networkRequestBuilder.setNetworkSpecifier(Integer.toString(mActiveSubId));
9.        }
10.        NetworkRequest networkRequest = networkRequestBuilder.build();
11.        mConnMgr.requestNetwork(
12.                networkRequest,
13.                mSuplConnectivityCallback,
14.                mHandler,
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.        private void evalRequest(NetworkRequestInfo n) {
2.          if (VDBG) {
3.                log("evalRequest");
4.                log(" n.requests = " + n.requested);
5.                log(" n.score = " + n.score);
6.                log(" mScore = " + mScore);
7.                log(" request.providerId = " + n.providerId);
8.                log(" mProvider.id = " + mProvider.getProviderId());
9.          }
10.          if (shouldNeedNetworkFor(n)) {
11.                if (VDBG) log("needNetworkFor");
12.                needNetworkFor(n.request, n.score);
13.                n.requested = true;
14.          } else if (shouldReleaseNetworkFor(n)) {
15.                if (VDBG) log("releaseNetworkFor");
16.                releaseNetworkFor(n.request);
17.                n.requested = false;
18.          } else {
19.                if (VDBG) log("done");
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.        private boolean shouldNeedNetworkFor(NetworkRequestInfo n) {
2.                // If this request is already tracked, it doesn't qualify for need
3.                return !n.requested
4.                    // If the score of this request is higher or equal to that of this factory and some
5.                    // other factory is responsible for it, then this factory should not track the request
6.                    // because it has no hope of satisfying it.
7.                    && (n.score < mScore || n.providerId == mProvider.getProviderId())
8.                    // If this factory can't satisfy the capability needs of this request, then it
9.                    // should not be tracked.
10.                    && n.request.canBeSatisfiedBy(mCapabilityFilter)
11.                    // Finally if the concrete implementation of the factory rejects the request, then
12.                    // don't track it.
13.                    && acceptRequest(n.request, n.score);
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
利用APN为mms的拨号示例代码如下:
1.        import android.net.ConnectivityManager;
2.        import android.net.Network;
3.        import android.net.NetworkCapabilities;
4.        import android.net.NetworkInfo;
5.        import android.net.NetworkRequest;
6.       
7.        private ConnectivityManager.NetworkCallback createConnectivityCallback(){
8.          return new ConnectivityManager.NetworkCallback() {
9.                @Override
10.                public void onAvailable(Network network) {
11.                    // Specific to a change to a SUPL enabled network becoming ready
12.                    Log.d(LOG_TAG, "test network connection available.");
13.                }
14.          
15.                @Override
16.                public void onLost(Network network) {
17.                    Log.d(LOG_TAG, "test network connection lost.");
18.                }
19.          
20.                @Override
21.                public void onUnavailable() {
22.                    Log.d(LOG_TAG, "test network connection request timed out.");
23.                    // Could not setup the connection to the network in the specified time duration.
24.          
25.                }
26.          };
27.        }
28.        //发起移动网络拨号
29.        private void startSecDataCall()
30.        {
31.          ConnectivityManager mTConnMgr;
32.          ConnectivityManager.NetworkCallback mConnectivityCallback = createConnectivityCallback();
33.          mTConnMgr = (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
34.             
35.          NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
36.          networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
37.          networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
38.          
39.          NetworkRequest networkRequest = networkRequestBuilder.build();
40.          mTConnMgr.requestNetwork(
41.                    networkRequest,
42.                    mConnectivityCallback,
43.                    20 * 1000);
44.        }
拨号成功后,可利用ifconfig指令查询网卡有没有辨认出来。
https://img-blog.csdnimg.cn/direct/faf7c7fec9104fd69354acaff4d4e2e4.png
9.2 访问

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

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 浅谈Android的ConnectivityService网络连接服务