2.3状态转换
上一小节中,调用onConnect 方法拨号后就接着调用transitionTo方法进入了DcActivatingState状态,
当RIL收到RIL_REQUEST_SETUP_DATA_CALL消息时, 将向DataConnection发送
EVENT_SETUP_DATA_CONNECTION_DONE的消息. DcActivatingState的processMessage方法
处理EVENT_SETUP_DATA_CONNECTION_DONE消息主要逻辑如下,
首先调用onSetupConnectionCompleted解析拨号结果,
ar = (AsyncResult) msg.obj;
cp = (ConnectionParams) ar.userObj;
DataCallResponse.SetupResult result = onSetupConnectionCompleted(ar);
然后根据拨号结果分别进行处理,
switch (result) {
case SUCCESS:
// All is well
mDcFailCause = DcFailCause.NONE;
transitionTo(mActiveState);
break;
case ERR_BadCommand:
•••
mInactiveState.setEnterNotificationParams(cp, result.mFailCause);
transitionTo(mInactiveState);
break;
•••
如果拨号成功就进入DcActiveState状态,
如果拨号过程中出现问题就进入DcInactiveState状态。
到此,和RIL交互已经告一段落了。接着看phone进程的处理。
直接分析正常的情况, DcActiveState状态。
DcActiveState进入时会调用enter方法, DcActiveState实现了自己的enter方法,如下,
首先通知其它APK,例如SystemUI,拨号成功。SystemUI会刷新界面的一些状态信息等等。
notifyAllOfConnected(Phone.REASON_CONNECTED);
当然,将信息传递给apk,一般有2种方法,
将相关信息通过广播发送出去,apk一般注册广播就可以了;
另外一种是通过回调接口,apk注册回调,直接监听状态就可以了。
但是对于phone信息,还可以通过TelephonyManager接口主动查询。
因此如何通知在此就不论述了。
然后更新DcNetworkAgent对象,通过DcNetworkAgent配置路由等,让终端可以真正的访问网络。对应的代码如下,
mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(),
"DcNetworkAgent", mNetworkInfo, makeNetworkCapabilities(), mLinkProperties, 50, misc);
2.4ConnectivityService管理网络
DcNetworkAgent是DataConnection的内部类,继承NetworkAgent。NetworkAgent又继承Handler,
DcNetworkAgent的构造方法直接调用父类NetworkAgent的构造方法, NetworkAgent的构造方法如下,
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
super(looper);
LOG_TAG = logTag;
mContext = context;
if (ni == null || nc == null || lp == null) {
throw new IllegalArgumentException();
}
if (VDBG) log("Registering NetworkAgent");
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将自己注册到ConnectivityService, 注意到此处的Messenger中包裹了NetworkAgent自身,
NetworkAgent继承自Handler,ConnectivityService将通过AsyncChannel与NetworkAgent进行跨进程通信。
ConnectivityManager的registerNetworkAgent方法如下,
public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
NetworkCapabilities nc, int score, NetworkMisc misc) {
try {
return mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc);
} catch (RemoteException e) {
return NETID_UNSET;
}
}
直接调用ConnectivityService的registerNetworkAgent方法进行注册。
ConnectivityService在SystemServer中构造和启动,因此属于systemserver进程,这样从phone进程到systemserver进程了,
当然这个点是通过AsyncChannel进行通信。
ConnectivityService管理android系统中所有和网络相关的,包括phone进程的数据网络,还包括wifi等等。
ConnectivityService的registerNetworkAgent调用流程图如下,
registerNetworkAgent方法如下,
//构造NetworkAgentInfo对象, 存储整个网络有关的信息
NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
new NetworkInfo(networkInfo), new LinkProperties(linkProperties),
new NetworkCapabilities(networkCapabilities), currentScore, mContext, mTrackerHandler,
new NetworkMisc(networkMisc), mDefaultRequest);
•••
//发送消息
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
一般跨进程调用之后都会发送消息转换到主线程中执行, ConnectivityService对该消息的处理如下,
case EVENT_REGISTER_NETWORK_AGENT: {
handleRegisterNetworkAgent((NetworkAgentInfo)msg.obj);
break;
}
handleRegisterNetworkAgent方法如下,
private void handleRegisterNetworkAgent(NetworkAgentInfo na) {
if (VDBG) log("Got NetworkAgent Messenger");
mNetworkAgentInfos.put(na.messenger, na);
assignNextNetId(na);
//mTrackerHandler与NetworkAgent的handler绑定在一起
na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger);
NetworkInfo networkInfo = na.networkInfo;
na.networkInfo = null;
updateNetworkInfo(na, networkInfo); //更新NetworkAgentInfo中的NetworkInfo
}
updateNetworkInfo方法主要逻辑如下,
首先通过binder机制调用NetworkManagementService创建网络,配置路由等网络属性,
if (networkAgent.isVPN()) {
mNetd.createVirtualNetwork(networkAgent.network.netId,
!networkAgent.linkProperties.getDnsServers().isEmpty(),
(networkAgent.networkMisc == null ||
!networkAgent.networkMisc.allowBypass));
} else {
mNetd.createPhysicalNetwork(networkAgent.network.netId,
networkAgent.networkCapabilities.hasCapability(
NET_CAPABILITY_NOT_RESTRICTED) ?
null : NetworkManagementService.PERMISSION_SYSTEM);
}
然后调用updateLinkProperties更新网络信息等。
最后调用rematchNetworkAndRequests方法理数据拨号产生的NetworkAgent对象。
1.NetworkManagementService
NetworkManagementService和ConnectivityService一样,在SystemServer中构造和启动,因此属于systemserver进程,
并不是一个单独的进程。因此,从ConnectivityService到NetworkManagementService是进程间的binder机制调用。
NetworkManagementService的createPhysicalNetwork方法如下,
public void createPhysicalNetwork(int netId, String permission) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
if (permission != null) {
mConnector.execute("network", "create", netId, permission);
} else {
mConnector.execute("network", "create", netId);
}
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
}
原来是调用NativeDaemonConnector类的execute方法完成。
NativeDaemonConnector是 NetworkManagementService和netd 守护进程通信的中间桥梁。
详细的机制见·····
2. updateLinkProperties方法如下,
updateLinkProperties最后都是通过NetworkManagementService,到netd守护进程完成网络属性的添加,
如果添加有问题,会直接断开网络。
注意:
ConnectivityService的updateNetworkInfo方法中有一段log很重要,
if (DBG) {
log(networkAgent.name() + " EVENT_NETWORK_INFO_CHANGED, going from " +
(oldInfo == null ? "null" : oldInfo.getState()) +
" to " + state);
}
明确地指出了当前的连接状态,比如,从
01-01 20:20:37.220 D/ConnectivityService( 459): NetworkAgentInfo [MOBILE (CDMA - EvDo rev. A) - 100] EVENT_NETWORK_INFO_CHANGED, going from null to CONNECTED
01-01 20:20:38.199 D/ConnectivityService( 459): NetworkAgentInfo [MOBILE (CDMA - EvDo rev. A) - 100] EVENT_NETWORK_INFO_CHANGED, going from CONNECTED to DISCONNECTED
小结:
数据业务的打开主要分为以下几个过程:
1,创建DataConnection 和 DcAsyncChannel对象, 将2个对象通过Handler绑定,通过AsyncChannel机制进行进程间的通信。
2,向RIL发送RIL_REQUEST_SETUP_DATA_CALL消息,进行拨号
3,完成状态从DcInactiveState 到 DcActivatingState 最后到 DcActiveState的转变
4,构造ConnectivityService 对象,注册。ConnectivityService将通过AsyncChannel与phone进程的NetworkAgent进行跨进程通信。
5,通过NetworkManagementService和netd守护进程进行交互,完成完成网络属性的添加,这样才算完成了拨号上网。