您的位置:首页 > 其它

Framework中的连接管理机制

2016-09-22 17:04 176 查看
http://blog.csdn.net/u010961631/article/details/48629601

上一节《Wifi服务框架介绍》介绍了WIFI的大致框架,本文主要介绍连接管理中的几个重要角色,包括:NetworkInfo、NetworkAgent、ConnectivityService、ConnectivityManager等。

为了便于讨论,本文选取一个具体问题展开分析,那就是:当当前的网络连接变为不可用时,系统如何自动切换其他可用的网络连接的。

我们知道,当手机在使用移动数据上网时,如果进入WIFI环境,手机将会自动连上WIFI使用数据,而当WIFI失去覆盖或者关闭WIFI时,手机又会自动连上移动数据,那么这个机制是如何实现的呢?本文从WIFI框架触发,跟踪当WIFI被disconnect时,如何切换为数据网络。


一、WifiStateMachine更新状态

WifiStateMachine利用setNetworkDetailedState()方法更新WIFI状态,如果WIFI网络被断开后,就会将DISCONNECTED的状态传递给setNetworkDetailedState(),此时WifiStateMachine就会把状态先同步到NetworkInfo,然后再更新到NetworkAgent对象:

[java] view
plain copy

private boolean setNetworkDetailedState(NetworkInfo.DetailedState state) {

boolean hidden = false;

if (state != mNetworkInfo.getDetailedState()) {

//更新NetworkInfo的状态

mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID());

if (mNetworkAgent != null) {

//将最新状态发送到NetworkAgent

mNetworkAgent.sendNetworkInfo(mNetworkInfo);

}

sendNetworkStateChangeBroadcast(null);

return true;

}

return false;

}

到这里就不得不介绍一下NetworkInfo和NetworkAgent了。


二、NetworkInfo介绍

NetworkInfo用于标识一个网络连接的状态、类型等属性的,从其提供的public方法我们就能看出其提供了一个网络连接最基本的信息:

[java] view
plain copy

@NetworkInfo.java

//获取网络类型,TYPE_MOBILE/TYPE_WIFI/TYPE_MOBILE_MMS等

public int getType() {}

//获取网络类型名称

public String getTypeName() {}

//网络是否是CONNECTED或者CONNECTING状态

public boolean isConnectedOrConnecting() {}

//网络是否是CONNECTED状态

public boolean isConnected() {}

//设置网络是否可用

public void setIsAvailable(boolean isAvailable) {}

//判断网络是否可用

public boolean isAvailable() {}

//是否漫游状态

public boolean isRoaming() {}

//设置漫游状态

public void setRoaming(boolean isRoaming) {}

//获取网络的state、mReason等信息

public DetailedState getDetailedState() {}

应用程序可以通过ConnectivityManager的getNetworkInfo()方法获取到该对象,并通过该对象查询当前的网络状态,比如可以这样获取当前是否有网络连接:

[java] view
plain copy

private boolean isNetworkConnected() {

final ConnectivityManager connectivity = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

if (connectivity == null) {

return false;

}

final NetworkInfo info = connectivity.getActiveNetworkInfo();

return info != null && info.isConnected();

}

上面是应用读取NetworkInfo的方法,那么当网络变化时,就应该由WIFI或者DATA去更新当前的NetworkInfo,而WifiStateMachine在setNetworkDetailedState中做的就是把当前的网络状态更新到NetworkInfo,即:

[java] view
plain copy

mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID());

更新完NetworkInfo之后,需要将其更新到ConnectivityManager才可被其他应用读取到,那么如何将其更新到ConnectivityManager呢?这就需要NetworkAgent来完成了。


三、NetworkAgent介绍

NetworkAgent的作用可以从其官方描述中略知一二:

[html] view
plain copy

"A Utility class for handling for communicating between bearer-specific code and ConnectivityService."

这句话描述了NetworkAgent的作用:他是某个网络连接与ConnectivityService之间的通讯的工具。

接下来我们通过代码来认识一下他究竟如何在网络连接与ConnectivityService之间进行通讯。

先来看一下这个类的定义:

[java] view
plain copy

public abstract class NetworkAgent extends Handler {}

我们发现,这是一个Handler的子类,并且他是一个抽象类(abstract),需要在子类中被实例化

然后来看其构造方法:

[java] view
plain copy

public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score) {

this(looper, context, logTag, ni, nc, lp, score, null);

}

public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {

super(looper);

mContext = context;

if (ni == null || nc == null || lp == null) {

throw new IllegalArgumentException();

}

//获取ConnectivityManager对象,并向其注册自己

ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( Context.CONNECTIVITY_SERVICE);

cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni), new LinkProperties(lp), new NetworkCapabilities(nc), score, misc);

}

我们看到其构造方法里面主要做了一件事情,获取ConnectivityManager对象,并通过registerNetworkAgent方式注册当前的NetworkAgent。

接下来我们插入两节来分别介绍另外两个对象:ConnectivityManager和ConnectivityService,然后再回头来看这里的registerNetworkAgent()方法。


四、ConnectivityService介绍

ConnectivityService是负责连接管理的大总管,他以Service的形式在系统初始化时就被创建:

[java] view
plain copy

@SystemServer.java

public static final String CONNECTIVITY_SERVICE = "connectivity";

private void startOtherServices() {

try {

//创建ConnectivityService

connectivity = new ConnectivityService(context, networkManagement, networkStats, networkPolicy);

//注册的name为"connectivity"

ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);

networkStats.bindConnectivityManager(connectivity);

networkPolicy.bindConnectivityManager(connectivity);

} catch (Throwable e) {

reportWtf("starting Connectivity Service", e);

}

}

从上面知道,该Service在SystemServer中的name为"Connectivity"。知道了这一点就够了,至于ConnectivityService本身我们暂且不去关注。


五、ConnectivityManager介绍

与其他众多Manager一样,ConnectivityManager也是在ContextImpl中被创建的:

[java] view
plain copy

@ContextImpl.java

registerService(CONNECTIVITY_SERVICE, new ServiceFetcher() {

public Object createService(ContextImpl ctx) {

IBinder b = ServiceManager.getService(CONNECTIVITY_SERVICE);

return new ConnectivityManager(IConnectivityManager.Stub.asInterface(b));

}});

从这里我们看到,创建ConnectivityManager时传递了一个name为CONNECTIVITY_SERVICE的服务对象,这个对象就是刚才我们向SystemServer注册的ConnectivityService。然后来看ConnectivityManager的构造方法:

[java] view
plain copy

@ConnectivityManager.java

public ConnectivityManager(IConnectivityManager service) {

mService = checkNotNull(service, "missing IConnectivityManager");

}

这里我们看到,构造方法里面只是将参数ConnectivityService传递给mService对象就完了。

好了,ConnectivityManager我们了解这么多就够了。下面继续我们NetworkAgent的初始化流程。


六、继续NetworkAgent初始化流程

现在我们继续NetworkAgent的初始化流程,这个流程中包含AsyncChannel的使用,不了解的同学可以在这里了解其使用方法和机制。


6.1、NetworkAgent向ConnectivityService注册过程

前面我们说道,NetworkAgent初始化的时候只做了一个事情,就是向ConnectivityManager注册自己,现在我们继续看该注册过程:

[java] view
plain copy

public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {

super(looper);

mContext = context;

if (ni == null || nc == null || lp == null) {

throw new IllegalArgumentException();

}

//获取ConnectivityManager对象,并向其注册自己

ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( Context.CONNECTIVITY_SERVICE);

cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni), new LinkProperties(lp), new NetworkCapabilities(nc), score, misc);

}

在调用注册方法时传递了六个参数,其中有三个比较重要的参数,都是从构造方法的参数中获取并重新new出来的,其分别是:

1、new Messenger(this)

2、new NetworkAgent(ni)

3、new NetworkCapabilities(nc)

需要注意的是,这里new出来的三个对象的来源,都应该是NetworkAgent子类被初始化时传递给构造方法的。

然后我们继续来看ConnectivityManager的registerNetworkAgent()方法。

[java] view
plain copy

@ConnectivityManager.java

public void registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, NetworkCapabilities nc, int score, NetworkMisc misc) {

try {

mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc);

} catch (RemoteException e) { }

}

经过前面的介绍我们现在知道,这里的mService就是ConnectivityService,继续来看接下来的流程:

[java] view
plain copy

@ConnectivityService.java

public void registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int currentScore, NetworkMisc networkMisc) {

//权限检查

enforceConnectivityInternalPermission();

//创建NetworkAgentInfo对象

NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),

new NetworkInfo(networkInfo), new LinkProperties(linkProperties),

new NetworkCapabilities(networkCapabilities), currentScore, mContext, mTrackerHandler,

new NetworkMisc(networkMisc));

synchronized (this) {

nai.networkMonitor.systemReady = mSystemReady;

}

//向自己Handler发送EVENT_REGISTER_NETWORK_AGENT消息

mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));

}

在ConnectivityService的registerNetworkAgent中做了两件事情:

1、创建NetworkAgentInfo对象;

2、向Handler发送EVENT_REGISTER_NETWORK_AGENT消息;

其中创建NetworkAgentInfo时,传递了九个参数,我们只关注其中三个,分别是:

1、messenger ----这个参数是registerNetworkAgent的参数,从NetworkAgent传递过来

2、new AsyncChannel() ----这是现在创建的新对象

3、new NetworkCapabilities(NetworkCapabilities) ----这也是用NetworkAgent传递过来的参数创建的对象

然后我们来看ConnectivityService对EVENT_REGISTER_NETWORK_AGENT的处理:

[java] view
plain copy

private class InternalHandler extends Handler {

public void handleMessage(Message msg) {

NetworkInfo info;

switch (msg.what) {

case EVENT_REGISTER_NETWORK_AGENT: {

handleRegisterNetworkAgent((NetworkAgentInfo)msg.obj);

break;

}

}

}

}

继续看handleRegisterNetworkAgent():

[java] view
plain copy

private void handleRegisterNetworkAgent(NetworkAgentInfo na) {

mNetworkAgentInfos.put(na.messenger, na);

assignNextNetId(na);

//向NetworkAgentInfo的asyncChannel对象发起连接请求

na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger);

NetworkInfo networkInfo = na.networkInfo;

na.networkInfo = null;

updateNetworkInfo(na, networkInfo);

}

这里我们看到,ConnectivityService向NetworkAgentInfo的asyncChannel对象发起connect请求,并且该AsyncChannel的srcHandler是mTrackerHandler,而dstMessenger对象是NetworkAgentInfo的messenger,那么这里的NetworkAgentInfo是哪里来的呢?

其实不难看出,这里的NetworkAgentInfo就是在registerNetworkAgent()中创建的,而dstMessenger自然就是NetworkAgent调用registerNetworkAgent()时传递进来的。

接下来,ConnectivityService将会利用获取到的NetworkAgent对象创建AsyncChannel双向通道。


6.2、ConnectivityService向NetworkAgent申请双向AsyncChannel过程

我们记得,NetworkAgent当初是这样调用registerNetworkAgent()的:

[java] view
plain copy

@NetworkAgent.java

public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {

ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( Context.CONNECTIVITY_SERVICE);

cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni), new LinkProperties(lp), new NetworkCapabilities(nc), score, misc);

}

因此ConnectivityService中的dstMessenger其实就是NetworkAgent,准确来说应该是NetworkAgent的子类。

从AsyncChannel的机制我们知道,当利用其发起connect请求时,其将会触发单向连接过程,此时srcHandler(也就是mTrackerHandler)将会收到CMD_CHANNEL_HALF_CONNECTED的消息:

[java] view
plain copy

private class NetworkStateTrackerHandler extends Handler {

public void handleMessage(Message msg) {

NetworkInfo info;

switch (msg.what) {

case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {

handleAsyncChannelHalfConnect(msg);

break;

}

}

}

}

继续来看handleAsyncChannelHalfConnect:

[java] view
plain copy

private void handleAsyncChannelHalfConnect(Message msg) {

AsyncChannel ac = (AsyncChannel) msg.obj;

if (mNetworkFactoryInfos.containsKey(msg.replyTo)) {

} else if (mNetworkAgentInfos.containsKey(msg.replyTo)) {

if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {

//向AsyncChannel发送消息

mNetworkAgentInfos.get(msg.replyTo).asyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);

} else {

}

}

}

这里我们看到,此刻ConnectivityService通过AsyncChannel向dstMessenger发送了CMD_CHANNEL_FULL_CONNECTION的消息,从AsyncChannel的机制我们想到,这个消息应该是在向NetworkAgent申请双向通道。

那么NetworkAgent究竟会如何处理该请求呢?

由于前面我们介绍过,NetworkAgent是抽象类,他需要在子类中被实例化,那么对于WIFI环境来说,他的子类就是在WifiStateMachine中的WifiNetworkAgent对象。

现在我们再回到WifiStateMachine中,我们可以看到,在L2ConnectedState状态机被初始化时将会创建WifiNetworkAgent对象:

[java] view
plain copy

class L2ConnectedState extends State {

@Override

public void enter() {

mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext, "WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter, mLinkProperties, 60);

}

}

然后来看该WifiNetworkAgent的定义:

[java] view
plain copy

@WifiStateMachine.java

private class WifiNetworkAgent extends NetworkAgent {

public WifiNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score) {

super(l, c, TAG, ni, nc, lp, score);

}

protected void unwanted() {

if (this != mNetworkAgent) return;

unwantedNetwork(network_status_unwanted_disconnect);

}

protected void networkStatus(int status) {

if (status == NetworkAgent.INVALID_NETWORK) {

unwantedNetwork(network_status_unwanted_disable_autojoin);

}

}

}

从这里我们看到,WifiNetworkAgent并没有覆盖父类NetworkAgent中的handleMessage方法,那么也就是说,当ConnectivityService向WifiNetworkAgent发送AsyncChannel请求时,该请求应该在NetworkAgent中被处理,也就是这里:

[java] view
plain copy

@NetworkAgent.java

public void handleMessage(Message msg) {

switch (msg.what) {

case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {

if (mAsyncChannel != null) {

} else {

//创建WifiNetworkAgent中的AsyncChannel对象

AsyncChannel ac = new AsyncChannel();

//完成双向通道连接动作

ac.connected(null, this, msg.replyTo);

ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, AsyncChannel.STATUS_SUCCESSFUL);

synchronized (mPreConnectedQueue) {

mAsyncChannel = ac;

for (Message m : mPreConnectedQueue) {

ac.sendMessage(m);

}

mPreConnectedQueue.clear();

}

}

break;

}

}

}

从这个handleMessage()中我们看到,对于ConnectivityService发起的CMD_CHANNEL_FULLY_CONNECTED申请,WifiNetworkAgent创建了自己的AsyncChannel对象并连接上然后发送了STATUS_SUCCESSFUL的消息。

经过以上过程,在ConnectivityService与WifiNetworkAgent之间就建立了双向的AsyncChannel通道。

以下是整个WifiNetworkAgent的初始化流程:




七、WIFI的断开过程

现在我们再回到WifiStateMachine对当前WIFI状态的更新过程中。当WIFI断开时,WifiStateMachine将会通过setNetworkDetailedState()更新当前WIFI的NetworkInfo对象,并将其传递给WifiNetworkAgent:

[java] view
plain copy

private boolean setNetworkDetailedState(NetworkInfo.DetailedState state) {

boolean hidden = false;

if (state != mNetworkInfo.getDetailedState()) {

//更新NetworkInfo的状态

mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID());

if (mNetworkAgent != null) {

//将最新状态发送到NetworkAgent

mNetworkAgent.sendNetworkInfo(mNetworkInfo);

}

sendNetworkStateChangeBroadcast(null);

return true;

}

return false;

}

然后我们来看NetworkAgent如何将最新的networkInfo传递到ConnectivityService中去:

[java] view
plain copy

@NetworkAgent.java

public void sendNetworkInfo(NetworkInfo networkInfo) {

queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo));

}

继续:

[java] view
plain copy

private void queueOrSendMessage(int what, Object obj) {

synchronized (mPreConnectedQueue) {

if (mAsyncChannel != null) {

//通过AsyncChannel发送请求

mAsyncChannel.sendMessage(what, obj);

} else {

Message msg = Message.obtain();

msg.what = what;

msg.obj = obj;

mPreConnectedQueue.add(msg);

}

}

}

到这里我们发现,NetworkAgent将最新的NetworkInfo作为一个Object放入一个EVENT_NETWORK_INFO_CHANGED的消息中,然后通过AsyncChannel发送出去。那么这个消息发送到哪里了呢?

此时我们应该能够想到,当初是ConnectivityService与WifiNetworkAgent创建了双向的AsyncChannel通道,那么此时的消息当然就会发送给ConnectivityService了,并且该消息将会在其NetworkStateTrackerHandler中被处理:

[java] view
plain copy

@ConnectivityService.java

private class NetworkStateTrackerHandler extends Handler {

public void handleMessage(Message msg) {

NetworkInfo info;

switch (msg.what) {

case NetworkAgent.EVENT_NETWORK_INFO_CHANGED: {

//拿到消息中最新的NetworkInfo信息

NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);

if (nai == null) {

loge("EVENT_NETWORK_INFO_CHANGED from unknown NetworkAgent");

break;

}

info = (NetworkInfo) msg.obj;

//通过updateNetworkInfo来进行更新

updateNetworkInfo(nai, info);

break;

}

}

}

}

然后我们继续来看updateNetworkInfo()的操作:

[java] view
plain copy

private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) {

NetworkInfo.State state = newInfo.getState();

NetworkInfo oldInfo = null;

synchronized (networkAgent) {

oldInfo = networkAgent.networkInfo;

//将最新的networkInfo更新到ConnectivityService

networkAgent.networkInfo = newInfo;

}

if (state == NetworkInfo.State.CONNECTED && !networkAgent.created) {

} else if (state == NetworkInfo.State.DISCONNECTED || state == NetworkInfo.State.SUSPENDED) {

//断开WIFI的NetworkAgent中的AsyncChannel

networkAgent.asyncChannel.disconnect();

}

}

在updateNetworkInfo()中,ConnectivityService将最新的NetworkInfo保存在networkAgent中,等待其他应用来获取。然后就向NetworkAgent的AsyncChannel发起disconnect()的请求,该请求将会在ConnectivityService中收到CMD_CHANNEL_DISCONNECTED的回应:

[java] view
plain copy

private class NetworkStateTrackerHandler extends Handler {

public void handleMessage(Message msg) {

NetworkInfo info;

switch (msg.what) {

case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {

handleAsyncChannelDisconnected(msg);

break;

}

}

}

}

继续来看handleAsyncChannelDisconnected():

[java] view
plain copy

private void handleAsyncChannelDisconnected(Message msg) {

NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);

if (nai != null) {

final ArrayList<NetworkAgentInfo> toActivate = new ArrayList<NetworkAgentInfo>();

for (int i = 0; i < nai.networkRequests.size(); i++) {

//当前网络断开,寻找可替代的网络连接

NetworkRequest request = nai.networkRequests.valueAt(i);

NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(request.requestId);

if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {

mNetworkForRequestId.remove(request.requestId);

sendUpdatedScoreToFactories(request, 0);

NetworkAgentInfo alternative = null;

}

}

}

}

在这里,将会取出当前断开的网络所能处理的NetworkRequest,然后在当前所有向ConnectivityService注册的列表中查找可替代的连接,并通过sendUpdatedScoreToFactories()向其发起连接请求:

[java] view
plain copy

private void sendUpdatedScoreToFactories(NetworkAgentInfo nai) {

for (int i = 0; i < nai.networkRequests.size(); i++) {

NetworkRequest nr = nai.networkRequests.valueAt(i);

if (!isRequest(nr)) continue;

sendUpdatedScoreToFactories(nr, nai.getCurrentScore());

}

}

继续:

[java] view
plain copy

private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) {

for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {

nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, 0, networkRequest);

}

}

到这里将会向新的连接的NetworkFactoryInfo对象发起CMD_REQUEST_NETWORK的请求,之后相应的连接对象就可以建立连接了。

至此,从一个连接类型遍转换到另一个连接类型中。

以下是该过程的流程图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: