关键字:Android,GPRS, APN, Service,Client, Connection, Tracker
我觉得软件设计过程的最难的一部分就是对现实世界进行抽象的过程,怎么把现实世界的物体和事件抽象成相应的类,而且要兼顾到多种复杂的应用场景,我觉得没有多年的设计功底是很困难的。相反,从茫茫代码之中,理出一条脉络要简单的多,特别android这么优秀的代码,有时不得不惊叹于编写者的高超技艺。
我觉得分析android的数据流程,对整个连接的过程的流程和框架有更清晰的把握,就必须站在对象的角度,现在以发起数据连接的过程,来解析各个对象和模块之间的怎么协调和运作的。
这是我提出来的数据连接的整体框架,分为若干个模块,各个模块又包含一些对象,下面详细解析一下这些模块。
一、UI部分
UI故名思议,就是userinterface用户界面,用户发起数据流程的连接或断开,最终都是要将结果反馈给用户,让用户明白当前的数据连接的状态。
这部分一个主要的对象是Settings对象(com.android.phone.Settings),通过如下代码向ConnectivityManager发起数据连接请求。
view plaincopy
- ConnectivityManager
cm = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); - cm.setMobileDataEnabled(mButtonDataEnabled.isChecked());
二、Mobile Data Service部分
这部分是相当于数据业务的中转站了,向上响应用户的请求,向下向telephony派发用户请求并处理来自telephony的状态变化。
这里面很重要的对象,包括:
1、ConnectivityService,ConnectivityManager是它的客户端,两者通过著名的binder机制通信(不是这里不是重点)进行通信,调用ConnectivityManager这里等同于调用到ConnectivityService。
2、MobileDataStateTracker,这是移动数据业务的"追踪器",又向telephony进行交互,它的对象组合在ConnectivityService对象里面,当然ConnectivityService对象还管理着其它的数据连接类型,包括WifiStateTracker。
代码流程走到这里,ConnectivityManager.java
view plaincopy
- public
void setMobileDataEnabled( booleanenabled) { -
try { -
mService.setMobileDataEnabled(enabled); -
} catch (RemoteException e) { -
} - }
ConnectivityService.java
view plaincopy
- public
synchronized void setMobileDataEnabled( booleanenabled) { -
if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] null)!= { -
if (DBG) "startingSlog.d(TAG, up " + mNetTrackers[ConnectivityManager.TYPE_MOBILE]); -
mNetTrackers[ConnectivityManager.TYPE_MOBILE].reconnect(); -
} - }
这里的mNetTrackers是一个MobileDataStateTracke,包含各种移动数据连接,包裹MMS,SUPL,DUN。
在MobileDataStateTracker.java里面的调用流程是这样的:
reconnect->mPhoneService.enableApnType(apnType);
mPhoneService是电话的服务的客户端,它的server端实际上是PhoneInterfaceManager对象(com.android.phone.PhoneInterfaceManager),
MobileDataStateTracker通过如下方式调用获取ITelephony接口的服务端:
view plaincopy
- mPhoneService
= "phone"));ITelephony.Stub.asInterface(ServiceManager.getService(
看PhoneInterfaceManager的enableApnType方法:
view plaincopy
- public
int enableApnType(String type) { -
enforceModifyPermission(); -
return mPhone.enableApnType(type); - }
这样,就将连接apn的请求发送到telephony框架层下去了。apn在设置应用里面有里面指定了,一般在你的工程目录下的system/etc/apns-conf.xml文件
三、Telephony部分
上面的mPhone是PhoneProxy对象,
调用流程:mPhone.enableApnType->mActivePhone.enableApnType(type)
mActivePhone是GSMPhone或者CDMAPhone的上溯接口PhoneBase对象
PhoneBase:里面mDataConnection.enableApnType(type);调用到
调用流程:enableApnType(Stringtype)->setEnabled->onEnableApn->onEnableNewApn
onEnableNewApn方法在DataConnectionTracker的派生类GsmDataConnectionTracker
以GSM为例,调用流程:onEnableNewApn->cleanUpConnection->conn.disconnect
conn是DataConnection对象,标识一钟数据连接,可以看出这里实际上实现了一个数据连接的状态机。
在DataConnection对象里面数据连接的状态分为
DcDefaultState,默认状态。
DcInactiveState,非激活状态。
DcActivatingState,正在激活状态
DcActiveState,激活状态
DcDisconnectingState,正在断开状态
DcDisconnectingBadDnsSta
状态转换如下图所示:
而动态图如下,
连接成功以后,notifyDefaultData调用到DefaultPhoneNotifier的notifyDataConnection方法。
DefaultPhoneNotifier是ITelephonyRegistry接口的客户端,其服务端是TelephonyRegistry(com.android.server.TelephonyRegistry)
TelephonyRegistry的notifyDataConnection方法调用如下语句
r是当前mRecords中的元素,包含有IPhoneStateListener接口的实现callback,TelephonyRegistry中的每个调用都会遍历mRecords中的元素,如果某个元素注册了对应接听,则调用callback的某个函数。
客户端通过如下方式调用取得电话状态的监听,以StatusBarPolicy.java中的mPhoneStateListener为例:
mPhoneStateListener是PhoneStateListener实例,PhoneStateListener实现了IPhoneStateListener接口,假如你继承PhoneStateListener子类,首先你要确定你感兴趣的监听事件,然后重写对应的方法。再像上面那样调用listen方法就可以了。
TelephonyRegistry的方法、监听动作、已经你要重写的方法对应关系如下:
TelephonyRegistry的方法
notifyServiceState
notifySignalStrength
notifyCallState
notifyDataConnection-------
notifyDataActivity
。。。。。。。。
因此整个调用链是:DefaultPhoneNotifier:notifyDataConnection---------》
除此之外,TelephonyRegistry还发出一个ACTION_ANY_DATA_CONNECTION_STATE_CHANGED,包含数据连接的详细信息。
而Mobile DataService里面的MobileDataStateTracker会接收到这个动作,由它的BoadcastReceiver类MobileDataStateReceiver提取出数据连接的信息,然后设置好状态
view plaincopy
- setDetailedState(DetailedState.CONNECTING,
reason, apnName);
MobileDataStateTracker根据状态变化给ConnectivityService发送EVENT_STATE_CHANGED消息。
ConnectivityService调用handleConnect去执行相关炒作,包括关闭优先级比它低的数据连接,更新状态栏等等