再论android 2.2数据连接过程
以前写过一篇android2.2的数据连接http://blog.csdn.net/yinlijun2004/article/details/6021007,
现在来看那边文章,截止就是一个类的注释一样,没有对整个上网框架的了解,也没有对流程有个很明确的解析,很多东西似懂非懂。
经过这几个月的工作和学习,对android的数据连接框架有了进一步的认识,虽然可能有些地方还是很不清晰,但还是决定在写一篇blog来复习一下。
关键字:Android,GPRS, APN, Service,Client, Connection, Tracker
我觉得软件设计过程的最难的一部分就是对现实世界进行抽象的过程,怎么把现实世界的物体和事件抽象成相应的类,而且要兼顾到多种复杂的应用场景,我 觉得没有多年的设计功底是很困难的。相反,从茫茫代码之中,理出一条脉络要简单的多,特别android这么优秀的代码,有时不得不惊叹于编写者的高超技 艺。
我觉得分析android的数据流程,对整个连接的过程的流程和框架有更清晰的把握,就必须站在对象的角度,现在以发起数据连接的过程,来解析各个对象和模块之间的怎么协调和运作的。
这是我提出来的数据连接的整体框架,分为若干个模块,各个模块又包含一些对象,下面详细解析一下这些模块。
一、UI部分
UI故名思议,就是user interface用户界面,用户发起数据流程的连接或断开,最终都是要将结果反馈给用户,让用户明白当前的数据连接的状态。
这部分一个主要的对象是Settings对象(com.android.phone.Settings),通过如下代码向ConnectivityManager发起数据连接请求。
- 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
- public void setMobileDataEnabled(boolean enabled) {
- try {
- mService.setMobileDataEnabled(enabled);
- } catch (RemoteException e) {
- }
- }
ConnectivityService.java
- public synchronized void setMobileDataEnabled(boolean enabled) {
- if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {
- if (DBG) Slog.d(TAG, "starting 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接口的服务端:
- mPhoneService = ITelephony.Stub.asInterface(ServiceManager.getService("phone"));
看PhoneInterfaceManager的enableApnType方法:
- 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);调用到 DataConnectionTracker的enableApnType方法
调用流程:enableApnType(String type)->setEnabled->onEnableApn->onEnableNewApn
onEnableNewApn方法在DataConnectionTracker的派生类GsmDataConnectionTracker和CdmaDataConnectionTracker中实现,从而区别不同类型PHONE的数据连接流程。
以GSM为例,调用流程:onEnableNewApn->cleanUpConnection->conn.disconnect
conn是DataConnection对象,标识一钟数据连接,可以看出这里实际上实现了一个数据连接的状态机。
在DataConnection对象里面数据连接的状态分为
DcDefaultState,默认状态。
DcInactiveState,非激活状态。
DcActivatingState,正在激活状态
DcActiveState,激活状态
DcDisconnectingState,正在断开状态
DcDisconnectingBadDnsState,断开状态(因为错误的DNS)
状态转换如下图所示:
而动态图如下,
连接成功以后,notifyDefaultData调用到DefaultPhoneNotifier的notifyDataConnection方法。
DefaultPhoneNotifier是ITelephonyRegistry接口的客户端,其服务端是TelephonyRegistry(com.android.server.TelephonyRegistry)
TelephonyRegistry的notifyDataConnection方法调用如下语句
r.callback.onDataConnectionStateChanged(state, networkType);
r是当前mRecords中的元素,包含有IPhoneStateListener接口的实现callback,TelephonyRegistry中的每个调用都会遍历mRecords中的元素,如果某个元素注册了对应接听,则调用callback的某个函数。
客户端通过如下方式调用取得电话状态的监听, 以StatusBarPolicy.java中的mPhoneStateListener为例:
((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE))
.listen(mPhoneStateListener,
PhoneStateListener.LISTEN_SERVICE_STATE
| PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
| PhoneStateListener.LISTEN_CALL_STATE
| PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
| PhoneStateListener.LISTEN_DATA_ACTIVITY);
mPhoneStateListener是PhoneStateListener实例,PhoneStateListener实现了 IPhoneStateListener接口,假如你继承PhoneStateListener子类,首先你要确定你感兴趣的监听事件,然后重写对应的方 法。再像上面那样调用listen方法就可以了。
TelephonyRegistry的方法、监听动作、已经你要重写的方法对应关系如下:
TelephonyRegistry的方法 ---------------------监听动作-------------------------------------------------------PhoneStateListener子类中的中的回调
notifyServiceState ---------- PhoneStateListener.LISTEN_SERVICE_STATE ----------------- public void onServiceStateChanged(ServiceState state)
notifySignalStrength ------- PhoneStateListener.LISTEN_SIGNAL_STRENGTHS --------- -- public void onSignalStrengthsChanged(SignalStrength signalStrength)
notifyCallState ---------------- PhoneStateListener.LISTEN_CALL_STATE ------------------------- public void onCallStateChanged(int state, String incomingNumber)
notifyDataConnection ------- PhoneStateListener.LISTEN_DATA_CONNECTION_STATE --- public void onDataConnectionStateChanged(int state, int networkType)
notifyDataActivity -------------- PhoneStateListener.LISTEN_DATA_ACTIVITY ----------------------- public void onDataActivity(int direction)
。。。。。。。。
因此整个调用链是:DefaultPhoneNotifier:notifyDataConnection ---------》 TelephonyRegistry :notifyDataConnection---------》 PhoneStateListener.callback:onDataConnectionStateChanged --------------》PhoneStateListener子类的onDataConnectionStateChanged
除此之外,TelephonyRegistry还发出一个ACTION_ANY_DATA_CONNECTION_STATE_CHANGED,包含数据连接的详细信息。
而Mobile Data Service里面的MobileDataStateTracker会接收到这个动作,由它的BoadcastReceiver类MobileDataStateReceiver提取出数据连接的信息,然后设置好状态
- setDetailedState(DetailedState.CONNECTING, reason, apnName);
MobileDataStateTracker根据状态变化给ConnectivityService发送EVENT_STATE_CHANGED消息。
ConnectivityService调用handleConnect去执行相关炒作,包括关闭优先级比它低的数据连接,更新状态栏等等。
很多地方还是没有写清楚,但是比上次进步很多,很多细节之处有待进一步研究。
未完待续。