以前寫過一篇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去執行相關炒作,包括關閉優先順序比它低的資料連線,更新狀態列等等。
很多地方還是沒有寫清楚,但是比上次進步很多,很多細節之處有待進一步研究。
未完待續。