Android網絡相關—上網流程 – Android移動開發技術文章_手機開發 Android移動開發教學課程

網絡應用,對於用戶來說,主要是搜索,瀏覽網頁,發email,發mms。對於android來說這些應用涉及到的一些中間過程,主要涉及到webkit,wap,smtp等協議,然後是socket通信,然後就是

linux內核的tcpip協議棧,及ppp協議,最後再是ttyS0之類的設備接口,最後由modem發送數據。另外手機的網絡接口可能不是modem,有可能是網卡或者wifi,那麼android中也有相應的接口可以添加。

不過有線網卡,目前用的比較少,畢竟手機或平板電腦上很少會用到體積大的網口。

 

先在總體上看一下網絡流程

這裡主要討論modem的形式。

 

 應用程序->觸發網絡連接(或已連接)->android本地的jni socket函數->內核中的BSD socket?->tcp/ip->ppp->/dev/ttySx(modem的數據口)。

 在觸發的網絡連接,如果沒有連接,則會時行撥號,撥號有一些初始化at命令,及一個撥號命令,atd*99***1#,這些實現是RIL.java與相 對應的ril.cpp文件中完成。撥號成功後,就進行ppp協商過程,ppp協商成功後,移動網絡會給終端分配ip地址,網關和dns地址。然後網絡連接 就成功瞭。之後就就是發送上層應用程序數據。

 

在我們的應用程序中,觸發瞭上網需求,系統會去檢測網絡是否連接,當然對於有多種接口,會輪詢,看哪一個連接可用(這裡應該是否有優先級,先有線,然後wifi,最後是modem,畢竟modem的費用是最高)

 

  在ppp撥號之前,所有的實現都包含在PhoneService中,即在frameworks/base/telephony/java/com/android/internal/telephony/目錄下,

  畢竟撥號這個動作還是屬於電話范疇。

  首先在PhoneApp.java中:onCreate

           PhoneFactory.makeDefaultPhones(this); //生成一個基本的電話服務形式

          

  在PhoneFactory.java中的:public static void makeDefaultPhone(Context context)中

                 int phoneType = getPhoneType(networkMode);

                if (phoneType == Phone.PHONE_TYPE_GSM) {

                    sProxyPhone = new PhoneProxy(new GSMPhone(context,

                            sCommandsInterface, sPhoneNotifier));

                    Log.i(LOG_TAG, "Creating GSMPhone");

                } else if (phoneType == Phone.PHONE_TYPE_CDMA) {

                    sProxyPhone = new PhoneProxy(new CDMAPhone(context,

                            sCommandsInterface, sPhoneNotifier));

                    Log.i(LOG_TAG, "Creating CDMAPhone");

                }

               //創建PhoneProxy,則PhoneProxy中,又創建GSMPhone,如果網絡是cdma,那麼則創建CDMAPhone。這裡不討論cdma制式的網絡。

  

   在GSMPhone.java的,構造函數中,mDataConnection = new GsmDataConnectionTracker (this);

   在GsmDataConnectionTracker.java中,GsmDataConnectionTracker類是繼承於DataConnectionTracker。在GsmDataConnectionTracker構造函數調用瞭createAllPdpList();函數在

   GsmDataConnectionTracker.java中。如下:

                   private void createAllPdpList() {

                    pdpList = new ArrayList<DataConnection>();

                    DataConnection pdp;

 

                    for (int i = 0; i < PDP_CONNECTION_POOL_SIZE; i++) {

                        pdp = new PdpConnection(mGsmPhone);

                        pdpList.add(pdp);

                     }

                }

                //創建瞭PDP_CONNECTION_POOL_SIZE個PdpConnection(PDP_CONNECTION_POOL_SIZE等於1)

                在應用程序觸發網絡發送數據,如觸發瞭onApnChanged,onRoamingOff,onRoamingOn等函數,或者處理消息時,會調用trySetupData函數

                對於trySetupData函數,剛會調用setupData(reason);進行數據連接。

                private boolean setupData(String reason) {

                    ApnSetting apn;

                    PdpConnection pdp;

 

                    apn = getNextApn();

                    if (apn == null) return false;

                    pdp = findFreePdp();

                    if (pdp == null) {

                        if (DBG) log("setupData: No free PdpConnection found!");

                        return false;

                    }

                    mActiveApn = apn;

                    mActivePdp = pdp;

 

                    Message msg = obtainMessage();

                    msg.what = EVENT_DATA_SETUP_COMPLETE;

                    msg.obj = reason;

                    pdp.connect(apn, msg);

 

                    setState(State.INITING);

                    phone.notifyDataConnection(reason);

                    return true;

                }

                //調用瞭pdp.connect(apn, msg)。時行撥號,即應該是往RIL.java層發送撥號請求瞭。

               

    接下來,看PdpConnection.java文件,繼承於DataConnection

        此文件實現瞭connect,disconnect等方法。

        在connect,setupDataCall接口方法

                 phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_GSM),

                Integer.toString(RILConstants.DATA_PROFILE_DEFAULT), apn.apn, apn.user,

                apn.password, Integer.toString(authType),

                obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE));

        mCM的類型是CommandsInterface,即是一些電話服務相碰的通用接口。這個接口的實現,就是RIL類,下面看RIL.java

       

  RIL.java完成android電話服務與modem操作的一轉換功能。即把一些電話服務轉換為實現的at命令,發送到modem

          在RIL類的中setupDataCall方法,實現如下:

          public void

        setupDataCall(String radioTechnology, String profile, String apn,

                String user, String password, String authType, Message result) {

            RILRequest rr

                    = RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result);

 

            rr.mp.writeInt(6);

 

            rr.mp.writeString(radioTechnology);

            rr.mp.writeString(profile);

            rr.mp.writeString(apn);

            rr.mp.writeString(user);

            rr.mp.writeString(password);

            rr.mp.writeString(authType);

 

            if (RILJ_LOGD) riljLog(rr.serialString() + "> "

                    + requestToString(rr.mRequest) + " " + radioTechnology + " "

                    + profile + " " + apn + " " + user + " "

                    + password + " " + authType);

 

            send(rr);

        }

        這個是通過socket方式給ril.cpp發送相關請求,引處發送RIL_REQUEST_SETUP_DATA_CALL請求,那麼在ril.cpp 就會相應的完成話往modem通過串口發送ATD*99***1#命令。最後回返at命令返回結果,成功的話,就會返回CONNECT OK,這時ril.cpp就會往RIL.java發送此命令成功的響應。在RIL.java中的run函數的循環中調用processResponse方 法進行解析相關的響應。

        processResponse()->processSolicited ()->case RIL_REQUEST_SETUP_DATA_CALL: ret =  responseStrings(p); break;再通過rr.mResult.sendToTarget(),把返回結果送到上一層模塊中。

       

        此時,系統會調用ppp撥號程序ppp的撥號源代碼在external/ppp目錄下。

        在Android1.6版本之前,系統封裝瞭調用pppd的代碼,在frameworks/base/telephony/java/com/android/internal/telephony/PppLink.java中。

        但之後就沒有瞭,網上的介紹說是用瞭高通的方案,把pppd與系統的進程的通信通過瞭內存共享的方式來實現,因此在代碼中就去掉瞭調用pppd的java代碼。

       

        如何共享?這是個問題。不過應該是系統的事瞭。

        那麼自己要手動進行pppd撥號瞭。

        什麼時候撥號?這個是關鍵。gprs畢竟是有流量。大傢都比較喜歡按需撥號,相當於智能撥號瞭。ppp已經提供瞭這個功能,加相應的參數即可。

       

        不過在新的android版本中,已經ppp代碼進行瞭簡化,沒有chat.c文件,那自然沒得有chat命令,也就無法用pppd call xxx這個命令。如果想用chat那麼就要自己移植ppp程序。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。