android 系统数据业务---打开(下)

来源:互联网 发布:unity3d 动画循环播放 编辑:程序博客网 时间:2024/05/16 09:16

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守护进程进行交互,完成完成网络属性的添加,这样才算完成了拨号上网。