1.网络管理概览 Android中提供的数据业务方式有几种:移动数据网络,WIFI,热点,网线等。这些数据业务本身可以独立使用,但是同一时刻,只能使用其中的一种数据业务方式。管理这些数据业务方式的使用由ConnectivityService,NetworkFactory,NetworkAgent,NetworkMonitor等来完成,ConnectivityService处于核心调度位置。
在公司项目中,引入了Tbox和车内以太网。这两类网络上网的方式主要替代原生的移动数据网络和以太网。
ConnectivityService主要和以下四个模块交互来完成网络管理:
网络有效性检测(NetworkMonitor)
网络评分机制(NetworkFactory)
路由配置信息的获取(NetworkAgent)
网络物理端口的设置(Netd)
Android网络管理架构如下图所示
当Android数据业务服务可用时,会将自己(NetworkFactory和NetworkAgent)注册到ConnectivityService中统一管理,ConnectivityService通过ping网络来检查网络的有效性(AOSP中的网址是墙外的网址,极有可能ping不通,因此项目中应该修改此网址,否则可能会导致期望的网络得不到上网权限),进而影响到各个数据业务方式的评分值,ConnectivityService通过这些评分值来决定以哪个数据业务方式连接网络。决定好数据业务方式后,把这些路由配置信息设置到网络物理设备中。这样我们的手机就可以正常上网了。
2.各个服务的初始化 2.1.1 ConnectivityService的初始化 ConnectivityService属于系统服务,在SystemServer中被启动。
SystemServer启动系统核心服务分为三个阶段:
启动引导服务,包含AMS PMS DMS PKMS等
启动核心服务:DropBox,Battery,UsageStats,WebViewUpdate等
启动其他服务:InputManagerService,WindowManagerService,ConnectivityService等
咱们的主角ConnectivityService就是在其他服务中被启动。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 private void run () { try { ...... String timezoneProperty = SystemProperties.get("persist.sys.timezone" ); if (timezoneProperty == null || timezoneProperty.isEmpty()) { Slog.w(TAG, "Timezone not set; setting to GMT." ); SystemProperties.set("persist.sys.timezone" , "GMT" ); } ...... if (!SystemProperties.get("persist.sys.language" ).isEmpty()) { final String languageTag = Locale.getDefault().toLanguageTag(); SystemProperties.set("persist.sys.locale" , languageTag); SystemProperties.set("persist.sys.language" , "" ); SystemProperties.set("persist.sys.country" , "" ); SystemProperties.set("persist.sys.localevar" , "" ); } Slog.i(TAG, "Entered the Android system server!" ); ...... android.os.Process.setThreadPriority( android.os.Process.THREAD_PRIORITY_FOREGROUND); android.os.Process.setCanSelfBackground(false ); Looper.prepareMainLooper(); System.loadLibrary("android_servers" ); createSystemContext(); mSystemServiceManager = new SystemServiceManager(mSystemContext); mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart); LocalServices.addService(SystemServiceManager.class, mSystemServiceManager); SystemServerInitThreadPool.get(); } finally { traceEnd(); } try { traceBeginAndSlog("StartServices" ); startBootstrapServices(); startCoreServices(); startOtherServices(); SystemServerInitThreadPool.shutdown(); } catch (Throwable ex) { ...... Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited" ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 private void startOtherServices () { final Context context = mSystemContext; VibratorService vibrator = null ; IStorageManager storageManager = null ; NetworkManagementService networkManagement = null ; NetworkStatsService networkStats = null ; NetworkPolicyManagerService networkPolicy = null ; ConnectivityService connectivity = null ; NetworkScoreService networkScore = null ; ...... if (!disableNetwork) { traceBeginAndSlog("StartNetworkManagementService" ); try { networkManagement = NetworkManagementService.create(context); ServiceManager.addService(Context.NETWORKMANAGEMENT_SERVICE, networkManagement); } catch (Throwable e) { reportWtf("starting NetworkManagement Service" , e); } traceEnd(); } ...... traceBeginAndSlog("StartNetworkStatsService" ); try { networkStats = NetworkStatsService.create(context, networkManagement); ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats); } catch (Throwable e) { reportWtf("starting NetworkStats Service" , e); } traceEnd(); traceBeginAndSlog("StartNetworkPolicyManagerService" ); try { networkPolicy = new NetworkPolicyManagerService(context, mActivityManagerService, networkStats, networkManagement); ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy); } catch (Throwable e) { reportWtf("starting NetworkPolicy Service" , e); } traceEnd(); traceBeginAndSlog("StartConnectivityService" ); try { connectivity = new ConnectivityService( context, networkManagement, networkStats, networkPolicy); ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity); networkStats.bindConnectivityManager(connectivity); networkPolicy.bindConnectivityManager(connectivity); } catch (Throwable e) { reportWtf("starting Connectivity Service" , e); } traceEnd(); }
初始化ConnectivityService的时候传入networkManagement,networkStats,networkPolicy。
2.1.2 获取其他服务的接口 ConnectivityService构造方法中接收交互服务的接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 mNetd = checkNotNull(netManager, "missing INetworkManagementService" ); mStatsService = checkNotNull(statsService, "missing INetworkStatsService" ); mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager" ); mPolicyManagerInternal = checkNotNull( LocalServices.getService(NetworkPolicyManagerInternal.class), "missing NetworkPolicyManagerInternal" );mTethering = new Tethering(mContext, mNetd, statsService, mPolicyManager, IoThread.get().getLooper(), new MockableSystemProperties()); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_USER_STARTED); intentFilter.addAction(Intent.ACTION_USER_STOPPED); intentFilter.addAction(Intent.ACTION_USER_ADDED); intentFilter.addAction(Intent.ACTION_USER_REMOVED); intentFilter.addAction(Intent.ACTION_USER_UNLOCKED); mContext.registerReceiverAsUser( mUserIntentReceiver, UserHandle.ALL, intentFilter, null , null ); mContext.registerReceiverAsUser(mUserPresentReceiver, UserHandle.SYSTEM, new IntentFilter(Intent.ACTION_USER_PRESENT), null , null ); mNetd.registerObserver(mTethering); mNetd.registerObserver(mDataActivityObserver);
2.2 NetworkFactory的初始化 NetworkFactory负责构建新增网络默认评分,网络类型,网络能力。为了车机启动起来就能按照网络评分机制来选择网络,ConnectivityService服务起来之后,就不断收集外部注册进来的网络(本文用Tbox注册网络和wifi注册网络来叙述)。
当管理Tbox的service起来之后,通过获取usb0(tbox通过usb0与车机通信)配置信息(usb0;12,13,14,15;ip=2.2.2.1/24 gateway=2.2.2.2 dns=116.116.116.116,8.8.8.8;0;70)。然后解析配置信息,解析获取网卡信息之后,创建一个NetworkFactory最后调用register()方法,将该网卡注册到ConnectivityService中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public void register () { this .log("Registering NetworkFactory" ); if (this .mMessenger == null ) { this .mMessenger = new Messenger(this ); ConnectivityManager.from(this .mContext).registerNetworkFactory(this .mMessenger, this .LOG_TAG); } } public void registerNetworkFactory (Messenger messenger, String name) { enforceConnectivityInternalPermission(); NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel()); mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi)); } private void handleRegisterNetworkFactory (NetworkFactoryInfo nfi) { if (DBG) log("Got NetworkFactory Messenger for " + nfi.name); mNetworkFactoryInfos.put(nfi.messenger, nfi); nfi.asyncChannel.connect(mContext, mTrackerHandler, nfi.messenger); }
2.3 NetworkAgent的初始化 NetworkAgent是一个网络代理,它里面保存了一些路由的配置信息,比如NetworkInfo,LinkProperties,NetworkCapabilities等。NetworkAgent的初始化都是在路由配置信息获取成功之后。比如打开数据开关,打开wifi开关等操作之后。
注: NetworkInfo 描述一个给定类型的网络接口的状态方面的信息,包括网络连接状态、网络类型、网络可连接性、是否漫游等信息 LinkProperties 描述一个网络连接属性信息(包含网络地址、网关、DNS、HTTP代理等属性信息 NetworkCapabilities 描述一个网络连接能力方面的信息,包括带宽、延迟等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 private boolean maybeHandleAsyncChannelMessage (Message msg) { switch (msg.what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { handleAsyncChannelHalfConnect(msg); break ; } ...... } private void handleAsyncChannelHalfConnect (Message msg) { AsyncChannel ac = (AsyncChannel) msg.obj; if (mNetworkFactoryInfos.containsKey(msg.replyTo)) { if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { if (VDBG) log("NetworkFactory connected" ); for (NetworkRequestInfo nri : mNetworkRequests.values()) { if (nri.request.isListen()) continue ; NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId); ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, (nai != null ? nai.getCurrentScore() : 0 ), 0 , nri.request); } } else { loge("Error connecting NetworkFactory" ); mNetworkFactoryInfos.remove(msg.obj); } } ...... } public void handleMessage (Message msg) { switch (msg.what) { case CMD_REQUEST_NETWORK: { handleAddRequest((NetworkRequest) msg.obj, msg.arg1, msg.arg2); break ; } ...... } }
当路由信息配置成功之后,ConnectivityService会通知NetworkFactory创建NetworkAgent。在handleAddRequest方法中会调用evalRequest根据评分,网络能力等来判断是否需要创建代理。
调用链路: handleAddRequest() –> evalRequest() –> needNetworkFor() –> NetworkFactory.startNetwork()–> ExtNetworkFactory.startNetwork() –> mayStartIpManager() –> startIpManager() –> new NetworkAgent()
2.4 NetworkMonitor的初始化 NetworkMonitor主要是检测网络有效性的,通过Http封装类去ping一个网站,根据ping网站的结果来影响评分值。因此,它的初始化是在NetworkAgent初始化之后,必须要获取到路由配置信息NetworkAgent后才会去初始化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public NetworkAgent (Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) { ...... this .netId = cm.registerNetworkAgent(new Messenger(this ), new NetworkInfo(ni), new LinkProperties(lp), new NetworkCapabilities(nc), score, misc); ...... } public int registerNetworkAgent (Messenger messenger, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int currentScore, NetworkMisc networkMisc) { final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(), new Network(reserveNetId()), new NetworkInfo(networkInfo), new LinkProperties( linkProperties), new NetworkCapabilities(networkCapabilities), currentScore,mContext, mTrackerHandler, new NetworkMisc(networkMisc), mDefaultRequest, this ); .... }
3. 网络有效性检测(NetworkMonitor) NetworkMonitor是一个状态机。负责检测网络有效性,也就是ping网络的过程。ping网络过程中产生的几种状态如下:
DefaultState 默认状态
EvaluatingState 验证状态
ValidatedState 验证通过状态
LingeringState 休闲状态,表示网络的验证位是真实的,并且曾经是满足特定NetworkRequest的最高得分网络,但是此时另一个网络满足了NetworkRequest的更高分数,在断开连接前的一段时间前,该网络被“固定”为休闲状态。
CaptivePortalState 强制门户状态
MaybeNotifyState 可能通知状态,表示用户可能已被通知需要登录。 在退出该状态时,应该小心清除通知。
以正常的ping网站过程为例,DefaultState为默认状态,NetworkMonitor接收到CMD_NETWORK_CONNECTED事件消息后,先由DefaultState状态处理,然后由EvaluatingState处理,最后交给ValidatedState处理。
从NetworkMonitor的初始化,到ping网站的过程,到ping网站的结果影响评分值。这个过程的时序图如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 rematchNetworkAndRequests(NetworkAgentInfo newNetwork, ReapUnvalidatedNetworks reapUnvalidatedNetworks, long now)
当网络状态变化,网络信息变化都会调用到rematchNetworkAndRequests方法中,最后会根据状态机状态,send不同类型的message,NetworkMonitor收到message之后进行相应的处理。
以收到CMD_NETWORK_CONNECTED为例,当monitor收到CMD_NETWORK_CONNECTED消息的时候,会将状态机切换到EvaluatingState状态,在EvaluatingState的enter()方法中发送CMD_REEVALUATE消息。在processMessage()中处理该消息。最后会调用到isCaptivePortal();中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 CaptivePortalProbeResult probeResult = isCaptivePortal(); if (probeResult.isSuccessful()) { transitionTo(mValidatedState); } else if (probeResult.isPortal()) { mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, mNetId, probeResult.redirectUrl)); mLastPortalProbeResult = probeResult; transitionTo(mCaptivePortalState); } else { final Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0 ); sendMessageDelayed(msg, mReevaluateDelayMs); logNetworkEvent(NetworkEvent.NETWORK_VALIDATION_FAILED); mConnectivityServiceHandler.sendMessage(obtainMessage( EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, mNetId, probeResult.redirectUrl)); if (mAttempts >= BLAME_FOR_EVALUATION_ATTEMPTS) { TrafficStats.clearThreadStatsUid(); } mReevaluateDelayMs *= 2 ; if (mReevaluateDelayMs > MAX_REEVALUATE_DELAY_MS) { mReevaluateDelayMs = MAX_REEVALUATE_DELAY_MS; } }
根据ping网络的结果来执行不同的操作:
ping网络成功 ,如果收到的响应码是204,将状态机切换到ValidatedState。当状态机切换到ValidatedState之后,在enter()方法中会发送消息EVENT_NETWORK_TESTED。当ConnectivityService收到EVENT_NETWORK_TESTED之后,调用updateCapabilities()更新网卡能力和重新评估这个网络是否对于所有请求是最优的;如果当前能ping通的网络评分和以前的评分不一致,调用sendUpdatedScoreToFactories()更新评分。
ping网络失败 ,网络返回200~399,转到CaptivePortalState状态处理。
ping网络失败 ,不是204,也不是200~399,则发送CMD_REEVALUATE消息,重新触发ping网络的动作。第一次失败,8s后重新ping网络,第二次失败,16s后重新ping网络,时间依次倍增,最长的时间间隔为10分钟。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 private boolean maybeHandleNetworkMonitorMessage (Message msg) {...... case NetworkMonitor.EVENT_NETWORK_TESTED: { final NetworkAgentInfo nai; synchronized (mNetworkForNetId) { nai = mNetworkForNetId.get(msg.arg2); } ..... if (valid != nai.lastValidated) { final int oldScore = nai.getCurrentScore(); ...... updateCapabilities(oldScore, nai, nai.networkCapabilities); if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai); } ..... break ; } ..... }
ping网络的状态会保存到NetworkAgentInfo中,而后续所有的评分值都会调用NetworkAgentInfo的getCurrentScore()方法来获取,getCurrentScore()方法会根据当前ping网络的状态重新计算评分值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 private int getCurrentScore (boolean pretendValidated) { if (networkMisc.explicitlySelected && (networkMisc.acceptUnvalidated || pretendValidated)) { return MAXIMUM_NETWORK_SCORE; } int score = currentScore; if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty()) { score -= UNVALIDATED_SCORE_PENALTY; } if (score < 0 ) score = 0 ; return score; }
3.网络评分机制 NetworkFactory的存在意义就是为了帮助ConnectivityService进行评分的管理。一般在NetworkFactory在初始化时,设置固定的评分值,作为评判的标准。 NetworkAgent作为一个代理信息的抽象,在其初始化时,也设置了固定的评分值,不过,这个评分值会根据当前的网络情况的不同而变化,其最后的评分值会和NetworkFactory中的固定评分值进行比较,从而筛选出最优网络。
项目中可能涉及的网络源如下:WifiNetworkFactory,TelephonyNetwork,EthernetNetwork,PhoneSwitcher,Tbox。
这些工厂在初始化的时候,会将默认评分注册到ConnectivityService中
NetworkFactory初始化
NetworkAgent初始化
NetworkMonitor中ping网络
disconnect
TelephonyNetwork
50
50
成功:+0 失败:-40 用户指定:+100
0
Tbox
50
50
成功:+0 失败:-40 用户指定:+100
0
Wifi
60
60
成功:+0 失败:-40 用户指定:+100
0
EthernetNetwork
69
69
成功:+0 失败:-40 用户指定:+100
0
PhoneSwitcher
101
101
成功:+0 失败:-40 用户指定:+100
0
各种数据业务类型的评分标准,除了其基础评分值不同之外,其他的评判标准都一样。其评分值的变化,主要有以下几种情况: 一.代理信息获取结束后,会参与ping网络的过程,如果ping网络成功,那么NetworkAgent中的评分值不变。如果ping网络失败,那么NetworkAgent中的评分值-40。如果用户指定了某种网络类型作为连接方式,那么NetworkAgent重的评分值+100。 二.如果NetworkAgent和ConnectivityService的AsyncChannel通道断开,需要设置其评分值为0,好让其他的评分高的网络类型连接。
NetworkFactory中的评分标准:
NetworkFactory中维持了基础的评分分值mScore,mScore只有在 NetworkFactory对象创建的时候才会赋值。因网络环境的变化导致需要重新进行网络评估时,使用基础评分分值与传进来的NetworkRequestInfo中的分值进行比较。
如果当前的NetworkRequestInfo没有requested过,且当前的分值score比基础分值mScore小,说明当前的NetworkRequestInfo为最优网络,调用needNetworkFor()连接网络。
如果当前的NetworkRequestInfo已经requested过,且当前的分值score比基础分值mScore大,说明当前的NetworkRequestInfo已经不是最优网络了,有个更优的网络可用连接,此时应该调用releaseNetworkFor()释放掉此类网络连接。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 private void evalRequest (NetworkRequestInfo n) { if (VDBG) log("evalRequest request = " + n.request + " with requested = " + n.requested); if (n.requested == false && n.score < mScore && n.request.networkCapabilities.satisfiedByNetworkCapabilities( mCapabilityFilter) && acceptRequest(n.request, n.score)) { if (VDBG) log(" needNetworkFor" ); needNetworkFor(n.request, n.score); n.requested = true ; } else if (n.requested == true && (n.score > mScore || n.request.networkCapabilities.satisfiedByNetworkCapabilities( mCapabilityFilter) == false || acceptRequest(n.request, n.score) == false )) { if (VDBG) log(" releaseNetworkFor" ); releaseNetworkFor(n.request); n.requested = false ; } else { if (VDBG) log(" done" ); } }
触发评分的过程:
1.NetworkFactory与ConnectivityService通过AsyncChannel建立连接的时候,初始化评分,并参与了第一次的评分过程。如果此时还没有ping网络的话,其传进来的评分值为基础评分值,以上代码会执行else逻辑。
2.调用sendUpdatedScoreToFactories()方法触发了评分过程 在ping网络过程中,会触发多次评分过程。在NetworkMonitor的多个状态中,都有向ConnectivityService发起EVENT_NETWORK_TESTED事件消息更新评分