Android啓用GPRS成功後反饋流程(MTK)

看此篇看不太懂的同志們可以先看看我另一篇文章:http://blog.csdn.net/yankebin/article/details/44035489
理解了建立GPRS通信的流程再來看這篇文章就相對來說好理解了

android通信流程本身就是一個很複雜的問題,我只是以我工作過程中遇到的細節爲主要線索,理一理整個過程中需要注意的地方,如有錯誤和不當,還望大家海涵和指正。

(1).先回過頭來看看數據網絡開啓過程中的CdmaDataConnection和GsmDataConnection中的onConnect()方法,該方法中在調用RIL的setupDataCall()時,傳入了標識爲EVENT_SETUP_DATA_CONNECTION_DONE 的Message,在RIL的setupDataCall()使用該Message獲取了RILRequest的實例並將該message作爲RIL Parcel的第一個元素寫入到其中。

RILRequest rr = RILRequest. obtain(RIL_REQUEST_SETUP_DATA_CALL, result);

該obtain方法作用是從池中檢索一個新的RILRequest實例,第一個參數是定義在RILConstants中以RIL_REQUEST_打頭的整型值,第二個參數是操作完成後要發送的東西。由此看來之前標識EVENT_SETUP_DATA_CONNECTION_DONE 的Message會在執行完後將發送出去。RILRequest,代表着一個即將發送出去的RIL請求,它裏面包含了Request請求號、序列號(自0開始累加)和保存請求結果的Message。

/**

 * Retrieves a new RILRequest instance from the pool.

 *

 * @param request RIL_REQUEST_*

 * @param result sent when operation completes

 * @return a RILRequest instance from the pool.

 */

static RILRequest obtain( int request, Message result) {

    RILRequest rr = null;

    synchronized(sPoolSync ) {

        if (sPool != null) {

            rr = sPool;

            sPool = rr.mNext ;

            rr. mNext = null;

            sPoolSize--;

        }

    }



    if (rr == null) {

        rr = new RILRequest();

    }

    synchronized(sSerialMonitor ) {

        rr. mSerial = sNextSerial++;

    }

    rr. mRequest = request;

    rr. mResult = result;

    rr. mp = Parcel.obtain();

  //這裏要求message不能爲空,並且已經關聯了相應的handler,看來在執行完操作之後發送的消息將由此handler接收並處理
 if (result != null && result.getTarget() == null) {

            throw new NullPointerException("Message target must not be null");

        }
    // first elements in any RIL Parcel

    rr. mp.writeInt(request);

    rr. mp.writeInt(rr.mSerial );



    return rr;

}

(2).當RILSender發送一個RIL請求後(即Android啓動GPRS流程(MTK)中(21)的send方法),rild收到請求後會進行分發,發送AT命令,若AT命令沒有得到響應回覆(分爲2種,請求迴應和主動上報),rild的分發線程被阻塞,java部分的RIL請求送出去後將得不到處理。當RIL請求得到正常處理時,RILReciver所在的線程(在RIL的構造方法中初始化)將接收到回送的response消息,並進行解析。



    //***** Instance Variables

   //定義在RIL類中的成員變量

    LocalSocket mSocket;

    HandlerThread mSenderThread;/

    RILSender mSender;

    Thread mReceiverThread;

    RILReceiver mReceiver;

   ------------------------------------------------------------------

public RIL(Context context, int preferredNetworkType, int cdmaSubscription) {
        super(context);
        if (RILJ_LOGD) {
            riljLog("RIL(context, preferredNetworkType=" + preferredNetworkType +
                    " cdmaSubscription=" + cdmaSubscription + ")");
        }    mCdmaSubscription  = cdmaSubscription;
        mPreferredNetworkType = preferredNetworkType;
        mPhoneType = RILConstants.NO_PHONE;

        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
        mWakeLock.setReferenceCounted(false);
        mWakeLockTimeout = SystemProperties.getInt(TelephonyProperties.PROPERTY_WAKE_LOCK_TIMEOUT,
                DEFAULT_WAKE_LOCK_TIMEOUT);
        mRequestMessagesPending = 0;
        mRequestMessagesWaiting = 0;
       //初始化SenderThread,RILSender
        mSenderThread = new HandlerThread("RILSender");
         mSenderThread.start();

         Looper looper = mSenderThread.getLooper();
         mSender = new RILSender(looper);

        ConnectivityManager cm = (ConnectivityManager)context.getSystemService(
                Context.CONNECTIVITY_SERVICE);
        if (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) {
            riljLog("Not starting RILReceiver: wifi-only");
        } else {
            riljLog("Starting RILReceiver");

           //初始化RILReceiver和mReceiverThread 

            mReceiver = new RILReceiver();
             mReceiverThread = new Thread(mReceiver, "RILReceiver");
             mReceiverThread.start();

            IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_SCREEN_ON);
            filter.addAction(Intent.ACTION_SCREEN_OFF);
            context.registerReceiver(mIntentReceiver, filter);
        }
    }

(3).RILReceiver實現了Runnable。因此這裏消息的接收應該在重寫的run方法中。該方法中先用一個外層的死循環來連接socket套接字的端點(endPoint,不太懂),但通過 s.connect(l);可能會連接不成功(原因不是很理解,之後再查吧),因此這裏如果嘗試不成功,會終止執行後面的代碼,開始下一次循環,記錄嘗試次數的變量retryCount 在這裏沒有看到太大用處,僅是用來根據其值輸出相應的日誌信息,連接成功後,重置了該retryCount,並將套接字賦值給了全局的變量mSocket ,此後開始其嵌套的內層死循環。內層死循環是從socket中獲取到rild的響應,通過readRilMessage(InputStream is, byte[] buffer)將回應寫入到buffer緩衝區裏,並返回消息的長度,之後再通過 p.unmarshall( buffer , 0, length)得到原始的字節(發送的時候進行了marshall處理),接下來就是通過 processResponse(p)進行消息的處理了,之後先設置當前radio的狀態,再關閉socket,重置RILRequest的序列號,並放回RILRequest池裏,清空mRequestsList ,最後再用notifyRegistrantsRilConnectionChanged通知所有的registrants(應該是監聽ril的吧,具體細節不知),ril已經連接或者斷開,當然這裏是通知斷開了。

  public void run() {

            int retryCount = 0;

            String socketRil = getRilSocketName( mySimId);

            try {

                for (;;) {//外層死循環,用來處理socket的連接

                LocalSocket s = null;

                LocalSocketAddress l;

                socketRil = getRilSocketName( mySimId);

          ..........



                try {

                    s = new LocalSocket();

                    l = new LocalSocketAddress(socketRil,

                            LocalSocketAddress.Namespace. RESERVED);

                    s.connect(l);

                } catch (IOException ex){

                    try {

                        if (s != null) {

                            s.close();

                        }

                    } catch (IOException ex2) {

                        //ignore failure to close after failure to connect

                    }

                    // don't print an error message after the the first time

                    // or after the 8th time

                    //官方源碼這裏值是8,註釋也可以看出來,這裏MTK做了修改,將值增大到16

                    if (retryCount == 16) {

                        Log. e (LOG_TAG,

                            "Couldn't find '" + socketRil

                            + "' socket after " + retryCount

                            + " times, continuing to retry silently" );

                    } else if (retryCount > 0 && retryCount < 16) {

                        Log. i (LOG_TAG,

                            "Couldn't find '" + socketRil

                            + "' socket; retrying after timeout" );

                    }

                    try {

                        Thread. sleep(SOCKET_OPEN_RETRY_MILLIS);

                    } catch (InterruptedException er) {

                    }

                    retryCount++;

                    continue;

                }

                retryCount = 0;

                mSocket = s;

                Log. i(LOG_TAG, "Connected to '" + socketRil + "' socket" );

                int length = 0;

                try {

                    InputStream is = mSocket.getInputStream();

                    for (;;) { //內層死循環用來從輸入流中讀取數據

                        Parcel p;

                         //readRilMessage是把以 little-endian 存儲的數據還原到本來的樣子

                    //以 little-endian 存儲時,數據低位存儲在內存低地址,數據高位存儲在內存高地址;

                    //read(buffer, offset, remaining); 讀入 remaining 長度的流數據;
                    //JVM 用 little-endian 存儲 int 型的 messageLength ,所以得用位操作轉換一下 

                        length = readRilMessage(is, buffer);



                        if (length < 0) {

                            // End-of-stream reached

                            break;

                        }
                        p = Parcel. obtain();
                        p.unmarshall( buffer, 0, length);//返回原始字節數據
                        p.setDataPosition(0);
                        //Log.v(LOG_TAG, "Read packet: " + length + " bytes");
                        processResponse(p);//處理迴應
                        p.recycle();
                    }
                } catch (java.io.IOException ex) {
                    Log. i(LOG_TAG, "'" + socketRil + "' socket closed" ,
                          ex);
                } catch (Throwable tr) {
                    Log. e(LOG_TAG, "Uncaught exception read length=" + length +
                        "Exception:" + tr.toString());
                }
                Log. i(LOG_TAG, "Disconnected from '" + socketRil
                      + "' socket");
                setRadioState (RadioState. RADIO_UNAVAILABLE);//存儲新的radio狀態爲無效狀態併發送通知
                try {
                    mSocket.close();
                } catch (IOException ex) {
                }
                mSocket = null;
                RILRequest. resetSerial();//重置序列號
                // Clear request list on close
                synchronized (mRequestsList ) {
                    for (int i = 0, sz = mRequestsList.size() ; i < sz ; i++) {
                        RILRequest rr = mRequestsList.get(i);
                        rr.onError( RADIO_NOT_AVAILABLE, null );
                        rr.release();//將RILRequest放回池中
                    }
                    mRequestsList.clear(); //清理請求列表
                }
            }} catch (Throwable tr) {
                Log. e(LOG_TAG, "Uncaught exception", tr);
            }
        //MTK-END [mtk04070][111121][ALPS00093395]Refined for supporting Gemini
            /* We're disconnected so we don't know the ril version */
            notifyRegistrantsRilConnectionChanged(-1);//通知所有的Registrants,ril的連接狀態改變
        }

(4).接下來看一下 processResponse(p)這裏的操作。主要是對消息的處理,這裏的分支是因爲爲了匹配定義在ril.cpp的常量值也就是AT的response的兩個分類,這兩個值分別是:RESPONSE_SOLICITED請求響應(對ril的請求響應,比如這裏的開啓數據網絡)和RESPONSE_UNSOLICITED非請求響應(主動響應,主動上報的,比如網絡狀態,短信,來電等)。因此processSolicited (p)是對數據網絡請求的迴應的處理。之後調用releaseWakeLockIfDone釋放喚醒鎖(喚醒鎖是一種機制用來表示有應用程序需要設備留在喚醒狀態)。

private void processResponse (Parcel p) {
        int type;
        type = p.readInt();
      //MTK修改開始
        /* Solve [ALPS00308613]Receive incoming VT call causes EE, mtk04070, 20120628 */
        if (mIsFirstResponse &&
            ((type == RESPONSE_UNSOLICITED) || (type == RESPONSE_SOLICITED))) {
            if (FeatureOption.MTK_VT3G324M_SUPPORT == false) {
                Log. d(LOG_TAG, "FeatureOption.MTK_VT3G324M_SUPPORT == false" );
                disableVTCapability();
            }
            mIsFirstResponse = false;
        }      
     //MTK修改結束
        if (type == RESPONSE_UNSOLICITED) {
            processUnsolicited (p);
        } else if (type == RESPONSE_SOLICITED) {
            processSolicited (p);
        }
        releaseWakeLockIfDone();
    }

(5).processSolicited(p)方法對響應進行處理。方法中從parcel讀取數據,根據讀取的serial(從Android啓用GPRS流程(MTK)的(21)中加入到mRequestsList)使用findAndRemoveRequestFromList找到RILRequest實例,再根據RILRequest的request值找到相應的分支。根據在setupDataCall(Android啓用GPRS流程(MTK) (20) )請求的code是RIL_REQUEST_SETUP_DATA_CALL找到該分支。該該分支中調用了responseSetupDataCall(p)方法對響應的結果進行解析,包括ip地址,網關,dns等等。如果解析發現有錯誤,將拋出異常。不管是否存在異常,都會將AR執行的返回結果放置到AsyncResult中,並賦值給RILRequest中的Message的obj,再通過sendToTarget()發送給調用者處理。這裏的Mssage最初是在GsmDataConnection或CdmaDataConnection中的onConnect()方法中創建的,其關聯的handler是StateMachine.java中的SmHandler,因此最終的消息處理在DataConnection.java中。進入到DataConnection.java,找到處理Message.what爲EVENT_SETUP_DATA_CONNECTION_DONE的地方。

private void processSolicited (Parcel p) {

        int serial, error;

        boolean found = false;

        serial = p.readInt();

        error = p.readInt();

        RILRequest rr;

        rr = findAndRemoveRequestFromList(serial);

        if (rr == null) {

            Log. w(LOG_TAG, "Unexpected solicited response! sn: "

                            + serial + " error: " + error);

            return;

        }

………..

    if (error == 0 || p.dataAvail() > 0) {

        // either command succeeds or command fails but with data payload

        try {switch (rr.mRequest) {

        /*

cat libs/telephony/ril_commands.h \

| egrep “^ *{RIL_” \

| sed -re ‘s/{([^,]+),[^,]+,([^}]+).+/case \1: ret = \2(p); break;/’

         */

        //接下來非常多的RIL請求處理,目測有幾十種(這裏省略部分)

        case RIL_REQUEST_GET_SIM_STATUS : ret =  responseIccCardStatus(p); break;

        .........

        case RIL_REQUEST_SEND_SMS : ret =  responseSMS(p); break;

        case RIL_REQUEST_SEND_SMS_EXPECT_MORE : ret =  responseSMS(p); break;

        case RIL_REQUEST_SETUP_DATA_CALL : ret =  responseSetupDataCall(p); break;

      .....

        case RIL_REQUEST_QUERY_MODEM_TYPE : ret = responseInts(p); break;



        default:

            throw new RuntimeException("Unrecognized solicited response: " + rr. mRequest);

        //break;

        }} catch (Throwable tr) {

            // Exceptions here usually mean invalid RIL responses

             //解析發現RILResponse存在錯誤,就會拋出異常

            Log. w(LOG_TAG, rr.serialString() + "< "

                    + requestToString(rr.mRequest)

                    + " exception, possible invalid RIL response" , tr);



            if (rr.mResult != null) {//只要message不爲空,仍然將其回送到調用者並由其進行處理

               AsyncResult. forMessage(rr.mResult, null, tr);//使用新構造一個AsyncResult ,並賦值給message的obj對象

                rr. mResult.sendToTarget();

            }

            rr.release();//將RILRequest放回池中

            return;

        }

    }



    if (error != 0) {

        rr.onError(error, ret);

        rr.release();

        return;

    }

    if (RILJ_LOGD ) riljLog(rr.serialString() + "< " + requestToString(rr.mRequest)

        + " " + retToString(rr.mRequest , ret));

    if (rr.mResult != null) {

      //解析正常,並且message存在,將AT執行的返回結果放到AsyncResult中,並賦值rr. mResult的obj,再由sendToTarget()回送到調用者並由其進行處理

        AsyncResult. forMessage(rr.mResult, ret, null);//賦值到rr.mResult的obj對象

        rr. mResult.sendToTarget();

    }

    rr.release();

}

//使用異常和處理的結果,及消息,新構造一個AsyncResult ,並賦值給message的obj對象,該變了obj的值,obj就包含了更多信息。

/* Saves and sets m.obj /

public static AsyncResult

forMessage (Message m, Object r, Throwable ex)

{

    AsyncResult ret;

   //此時m.obj是

    ret = new AsyncResult (m.obj , r, ex);

    m. obj = ret;

    return ret;

}

(6).DataConnection.java對EVENT_SETUP_DATA_CONNECTION_DONE的處理在DcActivatingState的processMessage()方法中。說明當ril的消息返回時,此時的連接狀態正處在激活中。msg當中包含的obj就是在上AsyncResult. forMessage()處理之後的AsyncResult,而AsyncResult中的userObj實際上就是在GsmDataConnection/CdmaDataConnection的OnConnect()方法當中封裝到Message當中的ConnectionParams。如果在RIL.java中處理AT的響應詳細有異常,AsyncResult中的成員變量result將爲null,如果沒有異常則成員變量exception爲null ,當從消息之中獲取到這些消息後,調用onSetupConnectionCompleted方法對AsyncResult進行處理和分類。只有當結果爲 DataCallState.SetupResult爲SUCCESS時纔會切換到ActiveState狀態.在切換到ActiveState狀態之前,先通過setEnterNotificationParams()方法將連接參數cp和failCause設置給DcActiveState狀態的成員變量mConnectionParams和mFailCause,在transitionTo到Activestate後,將會在其enter()方法中調用notifyConnectCompleted()將連接成功的消息發送出去。

/**

 * The state machine is activating a connection.

 */

private class DcActivatingState extends State {

    @Override

    public boolean processMessage(Message msg) {

        boolean retVal;

        AsyncResult ar;

        ConnectionParams cp;

      ........

      case EVENT_SETUP_DATA_CONNECTION_DONE :

                if (DBG ) log("DcActivatingState msg.what=EVENT_SETUP_DATA_CONNECTION_DONE");

                ar = (AsyncResult) msg. obj; //

                cp = (ConnectionParams) ar. userObj;

                DataCallState.SetupResult result = onSetupConnectionCompleted(ar);

                if (DBG ) log("DcActivatingState onSetupConnectionCompleted result=" + result);

                switch (result) {

                    case SUCCESS :

                        // All is well

                        mActiveState.setEnterNotificationParams(cp, FailCause.NONE);

                        transitionTo( mActiveState);

                        break;

                    case ERR_BadCommand ://指令錯誤

                        // Vendor ril rejected the command and didn't connect.

                        // Transition to inactive but send notifications after

                        // we've entered the mInactive state.

                        mInactiveState.setEnterNotificationParams(cp, result.mFailCause, -1);

                        transitionTo( mInactiveState);

                        break;

                    case ERR_UnacceptableParameter :

                        // The addresses given from the RIL are bad

                        tearDownData(cp);

                        transitionTo( mDisconnectingErrorCreatingConnection );

                        break;

                    case ERR_GetLastErrorFromRil : 

                          //獲取到了上一次RIL請求的消息,然後會切換到mInactiveState狀態去

                        // Request failed and this is an old RIL

                        phone.mCM .getLastDataCallFailCause(

                                obtainMessage( EVENT_GET_LAST_FAIL_DONE, cp));

                        break;

                    case ERR_RilError ://ril層存在錯誤

                        // Request failed and mFailCause has the reason

                        mInactiveState.setEnterNotificationParams(cp, result.mFailCause,

                                                                  getSuggestedRetryTime(ar));

                        transitionTo( mInactiveState);

                        break;

                    case ERR_Stale :

                        // Request is stale, ignore.

                        break;

                    default:

                        throw new RuntimeException("Unknown SetupResult, should not happen");

                }

                retVal = HANDLED;

                break;

      ........

}

(7).看看onSetupConnectionCompleted()方法都做是怎麼做的處理吧。先根據成員變量exception是否爲null判斷。如果不爲null根據exception的類型,判斷是屬於何種異常則關聯上相應的失敗原因。如果爲null,則判斷連接參數的tag值與當前的tag值是否一致(該值在DataConnection的DcInactiveState中的enter方法修改值並在EVENT_CONNECT發生時,放置到了ConnectionParams中),一致則說明是同一次網絡開啓請求的處理,否則則認爲本次響應的信息是錯誤的。即沒有異常,tag值也能匹配,並且響應的staus是正確的,說明本次開啓操作正確,接下來更新使用updateLinkProperty()方法更新LinkProperties(包括HttpProxy,會調用DataCallState中的setLinkProperties()方法,將DataCallState的成員變量ifname,addresses, dnses ,gateways 等關聯到LinkProperties中,ifname就是interface name對應apn創建成功之後的網絡設備名),並將狀態機切換到ActiveState狀態。

private DataCallState.SetupResult onSetupConnectionCompleted (AsyncResult ar) {

        DataCallState response = (DataCallState) ar.result;

        ConnectionParams cp = (ConnectionParams) ar.userObj;

        DataCallState.SetupResult result;

       if(ar.exception!=null) {

           if(DBG) {

                log("onSetupConnectionCompleted failed, ar.exception="+ ar.exception+

                   " response="+ response);

            }

           if(ar.exceptioninstanceofCommandException

                    && ((CommandException) (ar.exception)).getCommandError()

                    == CommandException.Error.RADIO_NOT_AVAILABLE) {

                result = DataCallState.SetupResult.ERR_BadCommand;

                result.mFailCause= FailCause.RADIO_NOT_AVAILABLE;

            }elseif((response ==null) || (response.version< 4)) {

                result = DataCallState.SetupResult.ERR_GetLastErrorFromRil;

            }else{

                result = DataCallState.SetupResult.ERR_RilError;

                result.mFailCause= FailCause.fromInt(response.status);

            }

        }elseif(cp.tag!=mTag) {//在EVENT_CONNECT發送時,mtag賦值到cp的tag,這裏進行匹配判斷,確定是否是同一次操作

           if(DBG) {

                log("BUG: onSetupConnectionCompleted is stale cp.tag="+ cp.tag+", mtag="+mTag);

            }

            result = DataCallState.SetupResult.ERR_Stale;

        }elseif(response.status!= 0) {

            result = DataCallState.SetupResult.ERR_RilError;

            result.mFailCause= FailCause.fromInt(response.status);

        }else{//

           if(DBG) log("onSetupConnectionCompleted received DataCallState: "+ response);

           cid= response.cid;

            result = updateLinkProperty(response).setupResult;

        }



       return result;

    }

(8).根據notifyConnectCompleted()名,明顯可以知道該方法是通知網絡連接完成用的。那來看看這個方法都做了些啥子東西。是怎麼把消息發送出去的。

private void notifyConnectCompleted(ConnectionParams cp, FailCause cause) {

                Log. e("YKB","notifyConnectCompleted-->ConnectionParams "+cp.apn.toString()+" msg:"+ cp.onCompletedMsg.toString());

                Message connectionCompletedMsg = cp.onCompletedMsg;

       if(connectionCompletedMsg==null) {

           return;

        }

       longtimeStamp = System.currentTimeMillis();

      //cid是上面第(7)點從response中取出的成員變量cid ;根據DataCallState註釋說是在ril.h中的,

     //查到源碼目 錄/hardware/ril/include/telephony/ril.h,

     //找到cid的註釋爲:Context ID, uniquely identifies this call



        connectionCompletedMsg.arg1=cid;



       if(cause == FailCause.NONE) {

           createTime= timeStamp;

            AsyncResult. forMessage(connectionCompletedMsg);

        }else{

           lastFailCause= cause;

           lastFailTime= timeStamp;

            AsyncResult. forMessage(connectionCompletedMsg, cause,

                                  newCallSetupException(mRetryOverride));

        }

       if(DBG) log("notifyConnectionCompleted at "+ timeStamp +" cause="+ cause);



        connectionCompletedMsg.sendToTarget();

    }

方法先從cp中取相應的Message,這個message是哪兒來的呢,回憶一下。在Android 啓用GPRS流程(MTK)中,當DataConnection.java的bringUp()方法時將傳遞過來的參數message和apnStting封裝成了ConnectionParams,所以這裏判斷的cp. onCompletedMsg就是傳遞給bringUp的那個參數Message,好吧。再回憶一下,這個message是在哪兒傳給bringUp()的。實際上這個message是在CdmaDataConnectionTracker和GsmDataConnectionTracker中的setupData()方法中進行構造的。

   Message msg = obtainMessage();

    msg.what= DctConstants.EVENT_DATA_SETUP_COMPLETE;

    msg.obj= reason;

    conn. bringUp(msg,mActiveApn) ;

接下來將唯一標識當前數據請求的id放置在message的arg1中,並根據記錄下當前的時間戳,然後將該Message又構造成一個一個AsyncResult實例。(爲什麼要構造成AsyncResult來進行傳遞,不是很明白)發送給相應的handler進行處理。由於在構造message時是使用的GsmDataConnectionTracker.java和CdmaDataConnectionTracker.java的obtainMessage方法,而這兩個Tracker繼承自DataConnectionTracker而DataConnectionTracker又繼承自Handler,因此該消息將在DataConnectionTracker中進行處理。

(9).DataConnectionTracker.java中的handleMessage方法中找到分支

(/frameworks/opt/telephony/src/java/com/android/internal/telephony/DataConnectionTracker.java)

case DctConstants.EVENT_DATA_SETUP_COMPLETE:

               mCidActive= msg.arg1;

                onDataSetupComplete((AsyncResult) msg.obj);

               break;

看到將arg1(也就是唯一的請求標識cid)賦值給了成員變量mCidActive 。比較簡單沒什麼說的,接下來還是看onDataSetupComplete()方法。不出意外的肯定又會分支到CdmaDataConnectionTracker和GsmDataConnectionTracker。

(10).先看CdmaDataConnectionTracker中onDataSetupComplete()方法吧

protected void onDataSetupComplete(AsyncResult ar) {

        String reason =null;

       if(ar.userObjinstanceofString) {

            reason = (String) ar.userObj;

        }

       if(isDataSetupCompleteOk(ar)) {

           // Everything is setup

            notifyDefaultData(reason);

        }else{

            FailCause cause = (FailCause) (ar.result);

           if(DBG) log("Data Connection setup failed "+ cause);



           // No try for permanent failure

           if(cause.isPermanentFail()) {

                notifyNoData(cause);

               return;

            }

           intretryOverride = -1;

           if(ar.exceptioninstanceofDataConnection.CallSetupException) {

                retryOverride =

                    ((DataConnection.CallSetupException)ar.exception).getRetryOverride();

            }

           if(retryOverride == RILConstants.MAX_INT) {

               if(DBG) log("No retry is suggested.");

            }else{

                startDelayedRetry(cause, reason, retryOverride);

            }

        }

    }

首先是將AsyncResult的uerObj成員變量取出來(CdmaDataConnectionTracker在構造EVENT_DATA_SETUP_COMPLETE時,傳遞的reason是字符串,而GsmDataConnectionTracker傳遞是ApnContext)。稍後使用DataConnectionTracker中的isDataSetupCompleteOk()對AsyncResult進行是否創建完成的判斷。

protected boolean isDataSetupCompleteOk(AsyncResult ar) {

       if(ar.exception!=null) {

           if(DBG) log("isDataSetupCompleteOk return false, ar.result="+ ar.result);

           returnfalse;

        }

       if(mFailDataSetupCounter<= 0) {

           if(DBG) log("isDataSetupCompleteOk return true");

           returntrue;

        }

        ar.result=mFailDataSetupFailCause;

       if(DBG) {

            log("isDataSetupCompleteOk return false"+

                   " mFailDataSetupCounter="+mFailDataSetupCounter+

                   " mFailDataSetupFailCause="+mFailDataSetupFailCause);

        }

       mFailDataSetupCounter-= 1;

       returnfalse;

    }

由於在成功返回構造AsyncResult只使用了Message,因此這裏AsyncResult的exception成員變量必定爲null,接下來是通過判斷CdmaDataConnectionTracker的成員變量mFailDataSetupCounter來決定數據連接的創建返回值。而mFailDataSetupCounter的值只有在接收到廣播

// Used for debugging. Send the INTENT with an optional counter value with the number

// of times the setup is to fail before succeeding. If the counter isn’t passed the

// setup will fail once. Example fail two times with FailCause.SIGNAL_LOST(-3)

// adb shell am broadcast \

// -a com.android.internal.telephony.dataconnectiontracker.intent_set_fail_data_setup_counter \

// –ei fail_data_setup_counter 3 – ei fail_data_setup_fail_cause -3

protectedstaticfinalStringINTENT_SET_FAIL_DATA_SETUP_COUNTER=

   "com.android.internal.telephony.dataconnectiontracker. intent_set_fail_data_setup_counter";

時纔會改變。根據該廣播的註釋可知它是用於調試的,用來記錄接續之前建立數據失敗的次數。實際上這裏沒什麼用,所以這裏通常都是返回成功的。因此將直接調用notifyDefaultData(String reason)通知網絡狀態改變了。

privatevoidnotifyDefaultData(String reason) {

    setState(DctConstants.State.CONNECTED);//修改狀態,在setState中會將CdmaDataConnectionTracker成員變量mState標記爲Connected

    notifyDataConnection(reason);//會調用到DataConnectionTracker.java中,該方法用來發送通知-所有活動的apn當前數據連接狀態。

和GsmDataConnectionTracker不同,GsmDataConnectionTracker重寫了這個方法。

    startNetStatPoll();//開始NetStat投票(作用不明確,暫時未理解)

    startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);//啓動數據失速警報(大概是在指定的一個時間後發出一個廣播INTENT_DATA_STALL_ALARM 這個指定的時間從Settings.Global取出)

   mDataConnections.get(0).resetRetryCount();//重置嘗試次數爲0

}

notifyDataConnection(reason);調用的是DataConnectionTracker.java方法,在該方法中通過PhoneBase的notifyDataConnection(string,string)把消息傳遞出去。

 protected void notifyDataConnection(String reason) {

       for(intid = 0; id < DctConstants.APN_NUM_TYPES; id++) {

           // Only active apns' state changed

           if(dataEnabled[id] &&mActiveApn!=null

                        &&mActiveApn.canHandleType(apnIdToType(id))) {

               mPhone.notifyDataConnection(reason, apnIdToType(id));

            }

        }

        notifyOffApnsOfAvailability(reason);

    }

再回到onDataSetupComplete(AsyncResult ar),如果失敗了,根據參數中ar攜帶的FailCause進行分支處理,如果FailCause是固定錯誤,則不會進行失敗嘗試(MTK這裏進行了修改,cause.isPermanentFail()始終返回的爲false),如果ar攜帶的異常類型是DataConnection.CallSetupException,則從取該異常的成員變量mRetryOverride進行重試數據建立建立

(11).回到GsmDataConnectionTracker.java的onDataSetupComplete(AsyncResult ar).由於在GsmDataConnectionTracker中的setupData()方法中進行構造Message傳遞的message的obj對象是ApnContext,因此這裏首先從ar中取出userobj進行類型判斷和強轉,如果類型不匹配,將拋出異常,反之則得到一個ApnConext實例。和CdmaDataConnectionTracker一樣,也是調用DataConnectionTracker的isDataSetupCompleteOk(ar)對數據連接完成進行確認的判斷,若爲false則需要進行相應的處理,處理之後使用trySetupData()方法對建立數據連接進行重試。如果爲ture,則從apnContext中取出DataConnectionAc實例,該實例是用來在不同handler之間進行消息傳遞的通道,這個DataConnectionAc的設置是在setupData(ApnContext apnContext)進行的,如果該實例不存在,則存在該錯誤,並進行數據連接重試,若存在,則再從apnContext中取出DataConnection和apnSetting的實例,並根據apnSetting中包含的端口號,代理信息構造ProxyProperties ,再由DataConnectionAc更新到當前LinkProperties上去。最後判斷一下當前的連接是不是default連接,並更新systemProperties(gsm.defaultpdpcontext.active),如果是默認連接且mPreferredApn 尚爲設置,則更新mPreferredApn 的引用。最後通過notifyDefaultData(apnContext)通知當前數據連接狀態;

@Override
 protected void onDataSetupComplete(AsyncResult ar) {

        DataConnection.FailCause cause = DataConnection.FailCause.UNKNOWN;//新構造的unkonw
       booleanhandleError =false;
        ApnContext apnContext =null;
       if(ar.userObjinstanceofApnContext){//obj的類型判斷
            apnContext = (ApnContext)ar.userObj;
        }else{
           thrownewRuntimeException("onDataSetupComplete: No apnContext");
        }

       if(isDataSetupCompleteOk(ar)) {
         //AsyncChannel to a DataConnection(數據連接的通信通道),DataConnectionAc 是爲了讓GsmDataConnectionTracker所在的
       //handler和DataConnection所在的Handler進行通信
            DataConnectionAc dcac = apnContext.getDataConnectionAc();
     ........
           if(dcac ==null) {//說明存在錯誤。
                log("onDataSetupComplete: no connection to DC, handle as error");
                cause = DataConnection.FailCause.CONNECTION_TO_DATACONNECTIONAC_BROKEN;
                handleError =true;//更新標誌位,表示需要處理錯誤,以便重新嘗試
            }else{
                DataConnection dc = apnContext.getDataConnection();
                ApnSetting apn = apnContext.getApnSetting();
               if(DBG) {
                    log("onDataSetupComplete: success apn="+ (apn ==null?"unknown": apn.apn));
                }
               //獲取端口號,代理信息,若存在就關聯到LinkProperties上去
               if(apn !=null&& apn.proxy!=null&& apn.proxy.length() != 0) {
                   try{
                        String port = apn.port;
                       if(TextUtils.isEmpty(port)) port ="8080";
                        ProxyProperties proxy =newProxyProperties(apn.proxy,
                                Integer. parseInt(port),null);
                        dcac.setLinkPropertiesHttpProxySync(proxy);
                    }catch(NumberFormatException e) {
                        loge("onDataSetupComplete: NumberFormatException making ProxyProperties ("+
                                apn.port+"): "+ e);
                    }
                }
               // everything is setup
          if(TextUtils.equals(apnContext.getApnType(),PhoneConstants.APN_TYPE_DEFAULT)) {
                    SystemProperties. set("gsm.defaultpdpcontext.active","true");
                   if(canSetPreferApn&&mPreferredApn==null) {
                       if(DBG) log("onDataSetupComplete: PREFERED APN is null");
                       mPreferredApn= apn;
                       if(mPreferredApn!=null) {
                            setPreferredApn(mPreferredApn.id);
                        }
                    }
                }else{
                    SystemProperties. set("gsm.defaultpdpcontext.active","false");
                }
               mTetheringExt.onDataSetupComplete(apnContext);
               // Notify call start again if call is not IDLE and not concurrent
               //如果當前gsm電話狀態不是空閒,並且語音通話和數據網絡不支持併發,那麼就要再次通知通話開始了
               if(((GsmCallTracker)mGsmPhone.getCallTracker()).state!= PhoneConstants.State.IDLE&&                    !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
                   if(DBG) log("onDataSetupComplete: In 2G phone call, notify data REASON_VOICE_CALL_STARTED");
                    notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED);
                }
                notifyDefaultData(apnContext);
               /// M: SCRI and Fast Dormancy Feature @{
               //MTK-START [mtk04070][111205][ALPS00093395]Add for SCRI
               /* Add by MTK03594 for SCRI feature */                               
                startScriPoll();               
               //MTK-END [mtk04070][111205][ALPS00093395]Add for SCRI
               /// @}
            }
     //isDataSetupCompleteOk(ar)爲false
        }else{
            cause = (DataConnection.FailCause) (ar.result);
           if(DBG) {
                ApnSetting apn = apnContext.getApnSetting();
                log(String. format("onDataSetupComplete: error apn=%s cause=%s",
                        (apn ==null?"unknown": apn.apn), cause));
            }

           if(cause.isEventLoggable()) {
               // Log this failure to the Event Logs.
               intcid = getCellLocationId();
                EventLog. writeEvent(EventLogTags .PDP_SETUP_FAIL,
                        cause.ordinal(), cid, TelephonyManager. getDefault().getNetworkType());
            }
           // Count permanent failures and remove the APN we just tried
           if(cause.isPermanentFail()) apnContext.decWaitingApnsPermFailCount();
           if(cause == DataConnection.FailCause.GMM_ERROR&&
                   mPhone.getServiceStateTracker().getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE) {
               // stop retry for GMM_ERROR and let GPRS attach event to trigger如果是GMM_ERROR停止重試,並且觸發GPRS附加事件
               //更新ApnConext中的成員變量mWaitingApns和mWaitingApnsPermanentFailureCountDown(此時mWaitingApns的size爲0)
               //mWaitingApnsPermanentFailureCountDown設置爲0,而0表示mWaitingApns中的所有的apn存在永久性錯誤
                apnContext.setWaitingApns(newArrayList<ApnSetting>());
                log("onDataSetupComplete: GMM_ERROR, wait for GPRS attach to retry.");
            }elseif(mGsmDCTExt.needDelayedRetry(cause.getErrorCode())) {//根據FailCause中的errorcode判斷是否需要重試
                log("onDataSetupComplete: need delayed retry");
               intretryCount = apnContext.getRetryCount();
               //配置一個簡單的線性序列的時間,加上一個隨機值
                apnContext.getDataConnection().configureRetry(2, 45000, 0);//重試參數(最大重試次數,延遲時間,隨機值介於0和第二個參數之間)
                apnContext.getDataConnection().setRetryCount(retryCount);
                apnContext.removeWaitingApn(apnContext.getApnSetting());//移除所以出於waiting狀態的apn
            }
           if(DBG) {
                log(String. format("onDataSetupComplete: WaitingApns.size=%d"+
                       " WaitingApnsPermFailureCountDown=%d",
                        apnContext.getWaitingApns().size(),
                        apnContext.getWaitingApnsPermFailCount()));
            }
            handleError =true;
        }
         //處理錯誤
       if(handleError) {
           // See if there are more APN's to try
           if(apnContext.getWaitingApns().isEmpty()) {
               if(apnContext.getWaitingApnsPermFailCount() == 0) {
                   if(DBG) {
                        log("onDataSetupComplete: All APN's had permanent failures, stop retrying");
                    }
                    apnContext.setState(DctConstants.State.FAILED);
                   mPhone.notifyDataConnection(Phone.REASON_APN_FAILED, apnContext.getApnType());
                    apnContext.setDataConnection(null);//清理DataConnection,在trySetupData將重新關聯新的實例
                    apnContext.setDataConnectionAc(null);//清理DataConnectionAc,在trySetupData將重新關聯新的實例
                   // M: try to enable apn which is in waiting list
                   if(apnContext.getApnType() == PhoneConstants.APN_TYPE_MMS) {
                        enableWaitingApn();
                    }
                   if(PhoneFactory.isDualTalkMode()) {
                       if(apnContext.getApnType() != PhoneConstants.APN_TYPE_DEFAULT&&mWaitingApnList.isEmpty()) {
                           // try to restore default
                            trySetupData(Phone.REASON_DATA_ENABLED, PhoneConstants.APN_TYPE_DEFAULT);
                        }
                    }                                                                                     
                }else{
                   if(DBG) log("onDataSetupComplete: Not all permanent failures, retry");

                   // check to see if retry should be overridden for this failure.

                   intretryOverride = -1;

                   if(ar.exceptioninstanceofDataConnection.CallSetupException) {

                        retryOverride =                    ((DataConnection.CallSetupException)ar.exception).getRetryOverride();
                    }
                   if(retryOverride == RILConstants.MAX_INT) {
                       if(DBG) log("No retry is suggested.");
                    }else{
                        startDelayedRetry(cause, apnContext, retryOverride);
                    }
                }
          //handleError爲false
            }else{
               if(DBG) log("onDataSetupComplete: Try next APN");
                apnContext.setState(DctConstants.State.SCANNING);
               // Wait a bit before trying the next APN, so that
               // we're not tying up the RIL command channel
                startAlarmForReconnect(APN_DELAY_MILLIS, apnContext);
            }
        }
    }

(12).來看看GsmDataConnectionTracker中的notifyDefaultData(apnContext)做了些什麼處理.和第(10)中CdmaDataConnectionTracker的notifyDefaultData(String)做的事情都差不多,更新ApnContext的狀態,開啓NetStatPoll,DataStallAlarm,重置重試次數,之後也是通過phoneBase的實例mPhone調用notifyDataConnection(string,string)把消息傳遞出去。Gsm和Cdma的分支在這裏又合併到一起。

private void notifyDefaultData(ApnContext apnContext) {       

       // M: If context is disabled and state is DISCONNECTING,

       // should not change the state to confuse the following enableApnType() which returns PhoneConstants.APN_ALREADY_ACTIVE as CONNECTED

       if(apnContext.getState() != DctConstants.State.DISCONNECTING) {

            apnContext.setState(DctConstants.State.CONNECTED);

        }

       // setState(DctConstants.State.CONNECTED);

       mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());

        startNetStatPoll();

        startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);

       // reset reconnect timer

        apnContext.setRetryCount(0);

    }

(13).PhoneBase繼承自handler,實現了Phone接口。在這個方法中又調用PhoneNotifier的來傳遞消息,它是對所有系統範圍狀態改變通知的抽象。DefaultPhoneNotifier實現了phoneNotifier,這裏實際上調用的DefaultPhoneNotifier的notifyDataConnection(Phone sender, String reason, String apnType, DataState state)方法.此外在getDataConnectionState(apntype)會分支到GSMPhone.java和CDMAPhone.java,返回相對應的PhoneConstants中的DataState枚舉類型(這裏是返回PhoneConstants.DataState.CONNECTED)

(frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneBase.java)

(frameworks/base/telephony/java/com/android/internal/telephony/PhoneConstants.java)

(frameworks/opt/telephony/src/java/com/android/internal/telephony/cdma/CDMAPhone.java)

(frameworks/opt/telephony/src/java/com/android/internal/telephony/gsm/GSMPhone.java)

 public void notifyDataConnection(String reason, String apnType) {

       mNotifier.notifyDataConnection(this, reason, apnType, getDataConnectionState(apnType));

    }

在DefaultPhoneNotifier中又調用了doNotifyDataConnection()方法,接下來就看看這個方法做了什麼處理

//MTK-START [mtk04070][111125][ALPS00093395]MTK modified

public void notifyDataConnection(Phone sender, String reason, String apnType,

            PhoneConstants.DataState state) {

        doNotifyDataConnection(sender, reason, apnType, state);

    }

//MTK-END [mtk04070][111125][ALPS00093395]MTK modified

(14).doNotifyDataConnection() 根據傳入的 apnType先從phone 中取出連接參數 linkProperties 和linkCapabilities( 代表鏈接功能的類 ),再獲取包含手機狀態和服務相關信息的 ServiceState實例,作爲之後TelephonyRegistry和 notifyDataStateChangeCallback()的參數。之後通過ITelephonyRegistry.aidl跨進程調用到 TelephonyRegistry.java的notifyDataConnection() 方法。
(frameworks/opt/telephony/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java)
(/frameworks/base/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl)

 private void doNotifyDataConnection(Phone sender, String reason, String apnType,
            PhoneConstants.DataState state) {
       //TODO
       // use apnType as the key to which connection we're talking about.
       // pass apnType back up to fetch particular for this one.
        TelephonyManager telephony = TelephonyManager. getDefault();//TelephonyManager 單列模式類,懶漢式,通過此方法獲取 TelephonyManager 實例
        LinkProperties linkProperties = null;
        LinkCapabilities linkCapabilities = null;
       booleanroaming =false;

       if(state == PhoneConstants.DataState.CONNECTED) {
            linkProperties = sender.getLinkProperties(apnType);
            linkCapabilities = sender.getLinkCapabilities(apnType);
        }
        ServiceState ss = sender.getServiceState();/
       if(ss !=null) roaming = ss.getRoaming();// 獲取到手機信息和服務信息類,獲取漫遊信息

       intnetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
       if(!FeatureOption.MTK_GEMINI_SUPPORT) {
     // 上面通過 getDefault獲取到telephony ,由於是懶漢式,所以不會爲 null
            networkType = ((telephony!= null) ? telephony.getNetworkType() : TelephonyManager.NETWORK_TYPE_UNKNOWN );
        } else{
            networkType = ((telephony!= null) ? telephony.getNetworkTypeGemini (sender.getMySimId()) : TelephonyManager.NETWORK_TYPE_UNKNOWN );
        }
        log( "doNotifyDataConnection " +"apnType="+ apnType + ",networkType="+ networkType +", state="+ state);
        notifyDataStateChangeCallback(
                state.toString(),
                reason,
                sender.getActiveApnHost(apnType),
                apnType,
                sender.isDataConnectivityPossible(apnType),
               mSimId);
       try{
          // 將 PhoneConstants.DataState轉換成 TelephoneManager當中定義的狀態。這裏是將 PhoneConstants.DataState. CONNECTED 轉換爲TelephonyManager.DATA_CONNECTED
            mRegistry.notifyDataConnection(
                    convertDataState(state),
                    sender.isDataConnectivityPossible(apnType),// 檢查該apn數據連接是否被允許,之後會通過調用到 PhoneBase.java,再分支到CdmaDataConnectionTracker和 GsmDataConnectionTracker的isDataPossible(String apnType) 方法
                    reason,
                    sender.getActiveApnHost(apnType), //返回或的apn 主機字符串 (其實是ApnSetting.apn)
                    apnType,
                    linkProperties,
                    linkCapabilities,
                    networkType,
                    roaming);
        } catch(RemoteException ex) {
           // system process is dead
        }

       // M: Update SIM indication state for data connection state change
       if(senderinstanceofPhoneBase) {
            ((PhoneBase)sender).updateDataStateOfSimIndication(apnType, state);
        }
    }

notifyDataStateChangeCallback() 根據方法名推測是一個數據狀態改變的回調

  private void notifyDataStateChangeCallback(String state, String reason, String apnName,
            String apnType, booleanunavailable,intsimId)
    {
        Iterator<IDataStateChangedCallback> iterator = mDataStateChangedCallbacks.iterator();
       while(iterator.hasNext()) {
            IDataStateChangedCallback callback = iterator.next();
            callback.onDataStateChanged(state, reason, apnName, apnType, unavailable, simId);
        }
    }

IDataStateChangedCallback 是一個接口,包含一個方法,該方法在 framework中沒有找到該接口的實現,推測是內置的系統級別應用程序進行實現。

public interface IDataStateChangedCallback {
       voidonDataStateChanged(String state, String reason, String apnName,
            String apnType, booleanunavailable,intsimId);
    }

(15).TelephonyRegistry的 notifyDataConnection()方法。首先是檢查是否有 notify權限( android.Manifest.permission.MODIFY_PHONE_STATE ),沒有權限的話,將不會繼續執行連接消息的傳遞。再判斷是否需要對目前的連接信息進行修改,如果有進行修改,則標記 modified爲true 。方法中 mRecords.events的實際上就是在NetworkController.java中註冊的消息,如果這些消息存在,並且 過IPhoneStateListener的 onDataConnectionStateChanged()回調觸發相應的處理,(之前進行過 LISTEN_DATA_CONNECTION_STATE 註冊的都將觸發,已知 NetworkController.java)。最後通過broadcastDataConnectionStateChanged () 發送網絡狀態改變的廣播出去, ConnectivityService.java中將接收到這個廣播,再繼續做處理。
(frameworks/base/services/java/com/android/server/TelephonyRegistry.java)

public void notifyDataConnection(intstate, booleanisDataConnectivityPossible,
            String reason, String apn, String apnType, LinkProperties linkProperties,
            LinkCapabilities linkCapabilities, intnetworkType,booleanroaming) {
       if(!checkNotifyPermission("notifyDataConnection()" )) {
           return;
        }
       synchronized(mRecords ) {
           // M: For synchronization of mRecords, move log into synchronization protection.
           if(DBG ) {
                Slog. i(TAG, "notifyDataConnection: state=" + state +" isDataConnectivityPossible="
                    + isDataConnectivityPossible + " reason='"+ reason
                    + "' apn='"+ apn +"' apnType=" + apnType +" networkType="+ networkType
                    + " mRecords.size()="+mRecords .size() +" mRecords="+ mRecords);
            }
           booleanmodified =false;
           if(state == TelephonyManager.DATA_CONNECTED) {// 數據已連接
               if(!mConnectedApns .contains(apnType)) {
                   mConnectedApns.add(apnType);//添加到連接的 apn列表中
                   if(mDataConnectionState != state) {//修改當前的成員變量標識連接狀態
                       mDataConnectionState= state;
                        modified = true;
                    }
                }
            } else{// 如果不是連接,則移除
               if(mConnectedApns .remove(apnType)) {
                   if(mConnectedApns .isEmpty()) {
                       mDataConnectionState= state;//連接狀態修改
                        modified = true;
                    } else{
                       // leave mDataConnectionState as is and
                       // send out the new status for the APN in question.
                    }
                }
            }
           mDataConnectionPossible= isDataConnectivityPossible;
           mDataConnectionReason= reason;
           mDataConnectionLinkProperties= linkProperties;
           mDataConnectionLinkCapabilities= linkCapabilities;
           if(mDataConnectionNetworkType != networkType) {//網絡連接類型修改
               mDataConnectionNetworkType= networkType;
               // need to tell registered listeners about the new network type
                modified = true;
            }
           if(modified) {
               if(DBG ) {
                    Slog. d(TAG, "onDataConnectionStateChanged(" +mDataConnectionState
                        + ", "+mDataConnectionNetworkType +")");
                }
               for(Record r :mRecords ) {
                    //PhoneStateListener. LISTEN_DATA_CONNECTION_STATE 偵聽更改數據連接狀態
                   if((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
                       try{
                              // 觸發IPhoneStateListener的 onDataConnectionStateChanged回調
                            r.callback.onDataConnectionStateChanged( mDataConnectionState,
                                   mDataConnectionNetworkType);
                        } catch(RemoteException ex) {
                           mRemoveList.add(r.binder );
                        }
                    }
                }
                handleRemoveListLocked();// mRemoveList 和 mRecords 是同步域,根據 mRemoveList的binder 移除mRecords中的 Record,
            }
        }
       broadcastDataConnectionStateChanged (state, isDataConnectivityPossible, reason, apn,
                apnType, linkProperties, linkCapabilities, roaming);
    }

(16)在framework 中NetworkController.java(/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java )的構造方法中調用了TelephonyManager的 listen方法進行註冊。監聽包括網絡服務狀態 (LISTEN_SERVICE_STATE), 信號強弱 (LISTEN_SIGNAL_STRENGTHS狀態欄的信號強度圖標 ),手機通話狀態(通話,空閒,響鈴 LISTEN_CALL_STATE),數據連接狀態 (LISTEN_DATA_CONNECTION_STATE),以及數據連接上的數據業務方向改變 (狀態欄使用它來顯示相應的數據流量圖標 )。

public NetworkController(Context context) {     
        ......

        ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
                Context. CONNECTIVITY_SERVICE);
       mHasMobileDataFeature= cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
      .......

       // set up the default wifi icon, used when no radios have ever appeared
        updateWifiIcons();
        updateWimaxIcons();
       // telephony
       mPhone= (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
//用的或運算將多種類型都帶進去了
        mPhone.listen(mPhoneStateListener ,
                          PhoneStateListener. LISTEN_SERVICE_STATE
                        | PhoneStateListener. LISTEN_SIGNAL_STRENGTHS
                        | PhoneStateListener. LISTEN_CALL_STATE
                        | PhoneStateListener. LISTEN_DATA_CONNECTION_STATE
                        | PhoneStateListener. LISTEN_DATA_ACTIVITY);
   .......

       // broadcasts
        IntentFilter filter = newIntentFilter();
        filter.addAction(WifiManager. RSSI_CHANGED_ACTION);
        filter.addAction(WifiManager. WIFI_STATE_CHANGED_ACTION);
        filter.addAction(WifiManager. NETWORK_STATE_CHANGED_ACTION );
        filter.addAction(TelephonyIntents. ACTION_SIM_STATE_CHANGED);
        filter.addAction(TelephonyIntents. SPN_STRINGS_UPDATED_ACTION );
        filter.addAction(ConnectivityManager. CONNECTIVITY_ACTION);
        filter.addAction(ConnectivityManager. INET_CONDITION_ACTION);
        filter.addAction(Intent. ACTION_CONFIGURATION_CHANGED );
        filter.addAction(Intent. ACTION_AIRPLANE_MODE_CHANGED );
  .......

    }

在框架中NetworkStatsService.java中也進行了TelephonyManager的listen方法進行PhoneStateListener. LISTEN_DATA_CONNECTION_STATE 註冊,不過貌似應該不會觸發。由於
COMBINE_SUBTYPE_ENABLED 恆爲true ,這裏只是提出來這個類有註冊的行爲。
(frameworks/base/services/java/com/android/server/net/NetworkStatsService.java)

public void systemReady() {
     .........

       // watch for networkType changes that aren't broadcast through
       // CONNECTIVITY_ACTION_IMMEDIATE above.
          // publicstaticfinalbooleanCOMBINE_SUBTYPE_ENABLED= true;
       if(!COMBINE_SUBTYPE_ENABLED ) {
           mTeleManager.listen(mPhoneListener ,LISTEN_DATA_CONNECTION_STATE);
        }
        registerPollAlarmLocked();
        registerGlobalAlert();
    }

(17).在系統內置的應用程序Settings中也調用了 TelephonyManager的listen 方法進行了 PhoneStateListener. LISTEN_DATA_CONNECTION_STATE註冊( 可能還有其他應用程序進行相同操作,但目前只發現 settings,內置程序phne中 /src/com/android/phone/CallNotifier.java進行了 PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR |PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR |PhoneStateListener.LISTEN_SERVICE_STATE單未進行 LISTEN_DATA_CONNECTION_STATE 的註冊)
(/packages/apps/Settings/src/com/android/settings/deviceinfo/Status.java)
(/packages/apps/Settings/src/com/android/settings/RadioInfo.java)
先來看下 Status.java

 protected void onResume() {
       super.onResume();
     ........
           mTelephonyManager.listen(mPhoneStateListener ,
                    PhoneStateListener. LISTEN_DATA_CONNECTION_STATE);
           mTelephonyManager.listen(mSignalStrengthListener ,
                PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
           mTelephonyManager.listen(mPhoneServiceListener ,
                PhoneStateListener.LISTEN_SERVICE_STATE);
         .......
}

再來看 RadioInfo.java

 protected void onResume() {
       .......
       mPhoneStateReceiver.registerIntent();
       mTelephonyManager.listen(mPhoneStateListener ,
                  PhoneStateListener. LISTEN_DATA_CONNECTION_STATE
                | PhoneStateListener.LISTEN_DATA_ACTIVITY
                | PhoneStateListener.LISTEN_CELL_LOCATION
                | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
                | PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
                | PhoneStateListener.LISTEN_CELL_INFO);
    }

(18.)接下來看下TelephonyManager的 listen方法實現( /frameworks/base/telephony/java/android/telephony/TelephonyManager.java ):根據相應的PhoneStateListener類型,在 TelephonyRegistry.java實現相應的listen 方法。

public void listen (PhoneStateListener listener, intevents) {
       //MTK-START [mtk04070][111116][ALPS00093395]Support Gemini
        String pkgForDebug = sContext!=null ?sContext.getPackageName() : "<unknown>";
       try{
          // getITelephony()返回ITelephony (frameworks/base/telephony/java/com/android/internal/telephony/ITelephony.aidl)
       // 由應用程序 Phone中的PhoneInterfaceManager 繼承ITelephony.Stub
            Boolean notifyNow = ( getITelephony() !=null);
           sRegistry.listen(pkgForDebug, listener.callback , events, notifyNow);

           /* Add by mtk01411 for Data related event */
           if(FeatureOption.MTK_GEMINI_SUPPORT) {         
               if(events == PhoneStateListener.LISTEN_NONE) {
                   /* Unregister previous listened events */
                   mRegistry2.listen(pkgForDebug, listener.callback , events, notifyNow);
                } elseif(events == PhoneStateListener.LISTEN_CALL_STATE) {
                   mRegistry2.listen(pkgForDebug, listener.callback , events, notifyNow);
                } else{
                   intdata_events = PhoneStateListener.LISTEN_NONE;
                   if((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) !=0 ) {
                        data_events |= PhoneStateListener. LISTEN_DATA_CONNECTION_STATE ;
                    }  
                   if((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) !=0 ) {
                        data_events |= PhoneStateListener. LISTEN_DATA_ACTIVITY;
                    }

                   if(data_events != PhoneStateListener.LISTEN_NONE) {
                       /* For 3rd party application: */
                       /* This solution is only useful if only one PS can be attached for one of two sim cards */
                       /* If PS can be attached on both sim cards at the same time: This solution can't work */
                       /* => Because the same callback may recevie two same events and can't identify which event comes from which sim card */
                       mRegistry2.listen(pkgForDebug, listener.callback , data_events, notifyNow);
                    }
                }

            }
       //MTK-END [mtk04070][111116][ALPS00093395]Support Gemini
        } catch(RemoteException ex) {
           // system process dead
            ex.printStackTrace();          
        } catch(NullPointerException ex) {
           // system process dead
            ex.printStackTrace();          
        }
    }

(19).回到TelephonyRegistry.java 來看看它的 listen方法實現

public void listen(String pkgForDebug, IPhoneStateListener callback, intevents,
           booleannotifyNow) {
       intcallerUid = UserHandle.getCallingUserId();// 多用戶的處理,獲取是調用的用戶 id
       intmyUid = UserHandle.myUserId();
       if(DBG ) {
            Slog. d(TAG, "listen: E pkg="+ pkgForDebug +" events=0x" + Integer.toHexString (events)
                + " myUid="+ myUid
                + " callerUid="+ callerUid);
        }
       if(events != 0) {
           /* Checks permission and throws Security exception */
            checkListenerPermission(events);

           synchronized(mRecords ) {
               // register
                Record r = null;
                find_and_add: {
                    IBinder b = callback.asBinder();
                   finalintN =mRecords .size();
                   for(int i = 0; i < N; i++) {
                        r = mRecords.get(i);
                       if(b == r.binder ) {
                           breakfind_and_add;
                        }
                    }
                    r = newRecord();
                    r. binder= b;
                    r.callback= callback;
                    r. pkgForDebug= pkgForDebug;
                    r. callerUid= callerUid;
                   mRecords.add(r);//加入到了 mRecords 中,在 notifyDataConnection中for 循環中使用
                   if(DBG ) Slog.i (TAG ,"listen: add new record="+ r);
                }
               intsend = events & (events ^ r.events );
                r. events= events;
               if(notifyNow) {
                   if((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
                       try{
                            r.callback.onServiceStateChanged( newServiceState(mServiceState ));
                        } catch(RemoteException ex) {
                            remove(r. binder);
                        }
                    }
                   if((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH ) != 0) {
                       try{
                           intgsmSignalStrength =mSignalStrength .getGsmSignalStrength();
                            r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
                                    : gsmSignalStrength));
                        } catch(RemoteException ex) {
                            remove(r. binder);
                        }
                    }
                   if((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
                       try{
                            r.callback.onMessageWaitingIndicatorChanged( mMessageWaiting);
                        } catch(RemoteException ex) {
                            remove(r. binder);
                        }
                    }
                   if((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
                       try{
                            r.callback.onCallForwardingIndicatorChanged( mCallForwarding);
                        } catch(RemoteException ex) {
                            remove(r. binder);
                        }
                    }
                   if(validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
                       try{
                            r.callback.onCellLocationChanged( newBundle(mCellLocation ));
                        } catch(RemoteException ex) {
                            remove(r. binder);
                        }
                    }
                   if((events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
                       try{
                            r.callback.onCallStateChanged( mCallState,mCallIncomingNumber );
                        } catch(RemoteException ex) {
                            remove(r. binder);
                        }
                    }
                   if((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
                       try{
                            r.callback.onDataConnectionStateChanged( mDataConnectionState,
                               mDataConnectionNetworkType);
                        } catch(RemoteException ex) {
                            remove(r. binder);
                        }
                    }
                   if((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
                       try{
                            r.callback.onDataActivity( mDataActivity);
                        } catch(RemoteException ex) {
                            remove(r. binder);
                        }
                    }
                   if((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
                       try{
                            r.callback.onSignalStrengthsChanged( mSignalStrength);
                        } catch(RemoteException ex) {
                            remove(r. binder);
                        }
                    }
                   if((events & PhoneStateListener.LISTEN_OTASP_CHANGED) != 0) {
                       try{
                            r.callback.onOtaspChanged( mOtaspMode);
                        } catch(RemoteException ex) {
                            remove(r. binder);
                        }
                    }
                   if(validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
                       try{
                           if(DBG_LOC ) Slog.d (TAG ,"listen: mCellInfo="+ mCellInfo);
                            r.callback.onCellInfoChanged( mCellInfo);
                        } catch(RemoteException ex) {
                            remove(r. binder);
                        }
                    }
                }
            }
        } else{
            remove(callback.asBinder());
        }
    }

(20).當TelephonyRegistry 的notifyDataConnection()方法中觸發 onDataConnectionStateChanged()時,實際上將回調到以下地方:具體都是做一些更新的操作

a.在framework 中NetworkController.java

 @Override
 publicvoidonDataConnectionStateChanged (intstate,intnetworkType) {
           if(DEBUG ) {
                Slog. d(TAG, "onDataConnectionStateChanged : state=" + state
                        + " type="+ networkType);
            }
           mDataState= state;
           mDataNetType= networkType;
            updateDataNetType();
            updateDataIcon();// 更新數據圖標
            refreshViews();// 刷新view
        }

b.在framework 中NetworkStatsService.java

private PhoneStateListener mPhoneListener=new PhoneStateListener() {
       @Override
       publicvoidonDataConnectionStateChanged (intstate,intnetworkType) {
           finalbooleanstateChanged = state !=mLastPhoneState ;
           finalbooleannetworkTypeChanged = networkType !=mLastPhoneNetworkType;
           if(networkTypeChanged && !stateChanged) {
               // networkType changed without a state change, which means we
               // need to roll our own update. delay long enough for
               // ConnectivityManager to process.
               //TODO: add direct event to ConnectivityService instead of
               // relying on this delay.
               if(LOGV ) Slog.v (TAG ,"triggering delayed updateIfaces()");
               mHandler.sendMessageDelayed(
                       mHandler.obtainMessage(MSG_UPDATE_IFACES), SECOND_IN_MILLIS);//發消息進行更新
            }
           mLastPhoneState= state;
           mLastPhoneNetworkType= networkType;
        }
    };

c.在應用程序Setting中 Status.java中:

private PhoneStateListener mPhoneStateListener= newPhoneStateListener() {
       @Override
       publicvoidonDataConnectionStateChanged (int state) {
            updateDataState();//
            updateNetworkType();
        }
    }

d.在應用程序Setting中 RadioInfo.java中:

public void onDataConnectionStateChanged(intstate) {
            updateDataState();
            updateDataStats();
            updatePdpList();
            updateNetworkType();
        }

(21).TelephonyRegistry的 notifyDataConnection()方法最後調用 broadcastDataConnectionStateChanged ()方法發送數據連接變化的廣播.這裏將當前的狀態, apn類型,連接參數等都封裝在了 action爲ACTION_ANY_DATA_CONNECTION_STATE_CHANGED_MOBILE的intent 中,通過intent將這些內容發送出去。之後 frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/toolbar/QuickSettingsConnectionModel.java 和/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/toolbar/SimSwitchPanel.java 將接收到該廣播並進行處理。

private void broadcastDataConnectionStateChanged( intstate,
           booleanisDataConnectivityPossible,
            String reason, String apn, String apnType, LinkProperties linkProperties,
            LinkCapabilities linkCapabilities, booleanroaming) {
       // Note: not reporting to the battery stats service here, because the
       // status bar takes care of that after taking into account all of the
       // required info.
        Intent intent =newIntent(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED_MOBILE);
        intent.putExtra(PhoneConstants. STATE_KEY, DefaultPhoneNotifier.convertDataState(state).toString());
       if(!isDataConnectivityPossible) {
            intent.putExtra(PhoneConstants. NETWORK_UNAVAILABLE_KEY,true );
        }
       if(reason !=null) {
            intent.putExtra(PhoneConstants. STATE_CHANGE_REASON_KEY, reason);
        }
       if(linkProperties !=null) {
            intent.putExtra(PhoneConstants. DATA_LINK_PROPERTIES_KEY, linkProperties);
            String iface = linkProperties.getInterfaceName();
           if(iface !=null) {
                intent.putExtra(PhoneConstants. DATA_IFACE_NAME_KEY, iface);
            }
        }
       if(linkCapabilities !=null) {
            intent.putExtra(PhoneConstants. DATA_LINK_CAPABILITIES_KEY , linkCapabilities);
        }
       if(roaming) intent.putExtra(PhoneConstants.DATA_NETWORK_ROAMING_KEY, true);

        intent.putExtra(PhoneConstants. DATA_APN_KEY, apn);
        intent.putExtra(PhoneConstants. DATA_APN_TYPE_KEY, apnType);

       if(FeatureOption.MTK_GEMINI_SUPPORT) {
            intent.putExtra(PhoneConstants. GEMINI_SIM_ID_KEY,mySimId );
        }

       // To make sure MobileDataStateTracker can receive this intent firstly,
       // using oredered intent ACTION_ANY_DATA_CONNECTION_STATE_CHANGED_MOBILE
       // redirect original intent. -->
       mContext.sendOrderedBroadcast(intent,null,mDataConnChangeReceiver, null, 0,null,null);
       // <--
    }

(21).在廣播ACTION_ANY_DATA_CONNECTION_STATE_CHANGED_MOBILE發送之後,將被 MobileDataStateTracker中的內部類MobileDataStateReceiver和 TelephonyRegistry的mDataConnChangeReceiver 接收。TelephonyRegistry中將接收到 intent又使用action :TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED發送出去。
而在 MobileDataStateReceiver中處理則比較複雜,這裏就沒有不再進行細緻分析了。先根據 intent中的apntype 從全局的trakerMap中取出相應的 tracker 實例,再根據PhoneConstants. STATE_KEY 取出 state值,並由此進行分支處理。在 CONNECTED 分支中, tracker調用setDetailedState() 修改apn對應的 networkinfo中的狀態信息,併發送EVENT_STATE_CHANGED消息 ,ConnectionService的內部類NetworkStateTrackerHandler 將接收該消息並進行處理。

@Override
public void onReceive(Context context, Intent intent) {
           if(intent.getAction().equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED_MOBILE)) {
                String apnType = intent.getStringExtra(PhoneConstants. DATA_APN_TYPE_KEY);
                MobileDataStateTracker tracker = mTrackerMap.get(apnType);
               if(tracker ==null) {
                   return;
                }
           ......
                   // 子類型改變了,發出相應的消息                                             
                tracker. mNetworkInfo.setSubtype(newSubType, subTypeName);
               if(newSubType != oldSubtype && tracker.mNetworkInfo.isConnected()) {
                    Message msg = tracker.mTarget.obtainMessage(EVENT_NETWORK_SUBTYPE_CHANGED,
                                                        oldSubtype, 0, tracker.mNetworkInfo );
                    msg.sendToTarget();
                }
                 // 根據intent中傳遞過來的字符串 state值再次轉換爲 PhoneConstants.DataState ,並根據 state進行分支處理
                PhoneConstants.DataState state = Enum. valueOf(PhoneConstants.DataState.class,
                        intent.getStringExtra(PhoneConstants. STATE_KEY));
                String reason = intent.getStringExtra(PhoneConstants. STATE_CHANGE_REASON_KEY);
                String apnName = intent.getStringExtra(PhoneConstants. DATA_APN_KEY);
                tracker.mNetworkInfo .setRoaming(intent.getBooleanExtra(PhoneConstants. DATA_NETWORK_ROAMING_KEY,false ));
               if(VDBG ) {
                    tracker.log(tracker. mApnType+" setting isAvailable to " +
                            !intent.getBooleanExtra(PhoneConstants. NETWORK_UNAVAILABLE_KEY,false ));
                }
               tracker.mNetworkInfo .setIsAvailable(!intent.getBooleanExtra(PhoneConstants. NETWORK_UNAVAILABLE_KEY,false ));

               if(tracker.mMobileDataState != state) {
                    tracker. mMobileDataState= state;
                   switch(state) {
                       caseDISCONNECTED:
                           if(tracker.isTeardownRequested()) {
                                tracker.setTeardownRequested( false);
                            }
                           if(FeatureOption.MTK_GEMINI_SUPPORT) {
                                tracker.setDetailedStateGemini(DetailedState. DISCONNECTED, reason, apnName, slot);
                            } else{
                                tracker.setDetailedState(DetailedState. DISCONNECTED, reason, apnName);
                            }
                           // can't do this here - ConnectivityService needs it to clear stuff
                           // it's ok though - just leave it to be refreshed next time
                           // we connect.
                           //if (DBG) log("clearing mInterfaceName for "+ mApnType +
                           //        " as it DISCONNECTED");
                           //mInterfaceName = null;
                           break;
                       caseCONNECTING:
                           if(FeatureOption.MTK_GEMINI_SUPPORT) {
                                tracker.setDetailedStateGemini(DetailedState. CONNECTING, reason, apnName, slot);
                            } else{
                                tracker.setDetailedState(DetailedState. CONNECTING, reason, apnName);
                            }
                           break;
                       caseSUSPENDED:
                           if(FeatureOption.MTK_GEMINI_SUPPORT) {
                                tracker.setDetailedStateGemini(DetailedState. SUSPENDED, reason, apnName, slot);
                            } else{
                                tracker.setDetailedState(DetailedState. SUSPENDED, reason, apnName);
                            }
                           break;
                       caseCONNECTED:
                            tracker. mLinkProperties= intent.getParcelableExtra(
                                    PhoneConstants. DATA_LINK_PROPERTIES_KEY);
                           if(tracker.mLinkProperties ==null) {
                                tracker.loge( "CONNECTED event did not supply link properties." );
                                tracker. mLinkProperties=new LinkProperties();
                            }
                            tracker. mLinkCapabilities= intent.getParcelableExtra(
                                    PhoneConstants. DATA_LINK_CAPABILITIES_KEY );
                           if(tracker.mLinkCapabilities ==null) {
                                tracker.loge( "CONNECTED event did not supply link capabilities." );
                                tracker. mLinkCapabilities=new LinkCapabilities();
                            }
                           if(FeatureOption.MTK_GEMINI_SUPPORT) {
                                tracker.setDetailedStateGemini(DetailedState. CONNECTED, reason, apnName, slot);
                            } else{
                                tracker.setDetailedState(DetailedState. CONNECTED, reason, apnName);
                            }

                           break;
                    }
                }
           .....
        }

privatevoid setDetailedState(NetworkInfo.DetailedState state, String reason,
            String extraInfo) {

       if(state !=mNetworkInfo .getDetailedState()) {
           booleanwasConnecting = (mNetworkInfo .getState() == NetworkInfo.State. CONNECTING);
            String lastReason = mNetworkInfo.getReason();
           /*
             * If a reason was supplied when the CONNECTING state was entered, and no
             * reason was supplied for entering the CONNECTED state, then retain the
             * reason that was supplied when going to CONNECTING.
             */
           if(wasConnecting && state == NetworkInfo.DetailedState.CONNECTED&& reason == null
                    && lastReason != null)
                reason = lastReason;
           mNetworkInfo.setDetailedState(state, reason, extraInfo);//修改networkInfo 中的狀態信息
            Message msg =mTarget.obtainMessage(EVENT_STATE_CHANGED, newNetworkInfo(mNetworkInfo ));//給ConnectionService 中NetworkStateTrackerHandler發消息
            msg.sendToTarget();
        } elseif(reason !=null&& (reason.equals(PhoneConstants. REASON_NO_SUCH_PDP) || reason.equals(Phone.REASON_APN_FAILED )) && state == DetailedState. DISCONNECTED){          
           mNetworkInfo.setDetailedState(state, reason, extraInfo);
            Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
            msg.sendToTarget();
        }
    }

(22).回到ConnectionService.java 中來,這裏果然是連接管理的最核心啊,也是反饋的終點了。

private class NetworkStateTrackerHandler extendsHandler {
     .....
       @Override
       publicvoidhandleMessage(Message msg) {
            NetworkInfo info;
           switch(msg.what ) {
               caseNetworkStateTracker.EVENT_STATE_CHANGED:
                    info = (NetworkInfo) msg. obj;
                   inttype = info.getType();
                    NetworkInfo.State state = info.getState();

                   if(VDBG || (state == NetworkInfo.State.CONNECTED) ||
                            (state == NetworkInfo.State. DISCONNECTED)) {
                        log("ConnectivityChange for "+
                            info.getTypeName() + ": "+
                            state + "/"+ info.getDetailedState());
                    }

                    EventLogTags.writeConnectivityStateChanged(
                            info.getType(), info.getSubtype(), info.getDetailedState().ordinal());

                   if(info.getDetailedState() ==
                            NetworkInfo.DetailedState. FAILED) {
                        handleConnectionFailure(info);
                    } elseif(info.getDetailedState() ==
                            DetailedState. CAPTIVE_PORTAL_CHECK) {
                        handleCaptivePortalTrackerCheck(info);
                    } elseif(state == NetworkInfo.State.DISCONNECTED) {
                        handleDisconnect(info);
                    } elseif(state == NetworkInfo.State.SUSPENDED) {
                       //TODO: need to think this over.
                       // the logic here is, handle SUSPENDED the same as
                       // DISCONNECTED. The only difference being we are
                       // broadcasting an intent with NetworkInfo that's
                       // suspended. This allows the applications an
                       // opportunity to handle DISCONNECTED and SUSPENDED
                       // differently, or not.
                        Slog. d(TAG, "Change to Suspend_State due to reason=" + info.getReason() +" with network="+ info.getSubtypeName()) ;
                       if(((info.getReason() !=null) && info.getReason().equals(Phone.REASON_VOICE_CALL_STARTED ))
                                && (info.getSubtype() == TelephonyManager. NETWORK_TYPE_GPRS
                                        || info.getSubtype() == TelephonyManager.NETWORK_TYPE_EDGE
                                        || info.getSubtype() == TelephonyManager.NETWORK_TYPE_UNKNOWN)) {
                            Xlog.e( MTK_TAG,"Suspend PS TX/RX Temporarily without deactivating PDP context");
                            sendSuspendedBroadcast(info);// 手機2G網絡掛起
                        } else{
                            Xlog.e( MTK_TAG,"Switch to Suspend:invoke handleDisconnect()" );
                            handleDisconnect(info);// 做斷開處理
                        }
                    } elseif(state == NetworkInfo.State.CONNECTED) {
                        handleConnect(info);// 做連接處理
                    }
                   if(mLockdownTracker !=null) {
                       mLockdownTracker.onNetworkInfoChanged(info);
                    }
                   break;
             .......
            }
        }
    }

(23.)最後一步操作了,根據NetworkInfo對應狀態變化執行 handleConnect(進行Connected 處理)或者 handleDisconnect(Disconnected)處理。併發出 CONNECTIVITY_ACTION 的廣播,該廣播是一個公共廣播,應用程序或者框架中都可以進行廣播的接收。消息傳遞給應用程序,知曉了網絡的連接狀況已經改變,並且可以獲取到具體當前的網絡狀態

private void handleDisconnect(NetworkInfo info) {
………

   /*
     * If the disconnected network is not the active one, then don't report
     * this as a loss of connectivity. What probably happened is that we're
     * getting the disconnect for a network that we explicitly disabled
     * in accordance with network preference policies.
     */
   if(!mNetConfigs [prevNetType].isDefault()) {
        List pids = mNetRequestersPids[prevNetType];
       for(int i = 0; i<pids.size(); i++) {
            Integer pid = (Integer)pids.get(i);
           // will remove them because the net's no longer connected
           // need to do this now as only now do we know the pids and
           // can properly null things that are no longer referenced.
            reassessPidDns(pid.intValue(), false);
        }
    }

    Intent intent =new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
    intent.putExtra(ConnectivityManager. EXTRA_NETWORK_INFO, new NetworkInfo(info));
    intent.putExtra(ConnectivityManager. EXTRA_NETWORK_TYPE, info.getType());
   if(info.isFailover()) {
        intent.putExtra(ConnectivityManager. EXTRA_IS_FAILOVER,true );
        info.setFailover( false);
    }
   if(info.getReason() !=null) {
        intent.putExtra(ConnectivityManager. EXTRA_REASON, info.getReason());
    }
   if(info.getExtraInfo() !=null) {
        intent.putExtra(ConnectivityManager. EXTRA_EXTRA_INFO,
                info.getExtraInfo());
    }

   if(mNetConfigs [prevNetType].isDefault()) {

       /** M: Support CMCC Wi-Fi to Mobile @{ */
       booleanmobileData = getMobileDataEnabled();
        log("mobileData="+ mobileData + ", prevNetType="+ prevNetType +",mActiveDefaultNetwork "+mActiveDefaultNetwork);

       if(mIcsExt ==null){
           log("Null in mIcsExt");
          return;
        }

       if(mIcsExt .isDefaultFailover(prevNetType,mActiveDefaultNetwork)){
            isFailover = tryFailover(prevNetType);
           if(mActiveDefaultNetwork != -1) {
                NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork ].getNetworkInfo();
                intent.putExtra(ConnectivityManager. EXTRA_OTHER_NETWORK_INFO, switchTo);
            } else{
               mDefaultInetConditionPublished= 0;// we're not connected anymore
                intent.putExtra(ConnectivityManager. EXTRA_NO_CONNECTIVITY,true );
            }
        } else{
           mDefaultInetConditionPublished= 0;// we're not connected anymore
            intent.putExtra(ConnectivityManager. EXTRA_NO_CONNECTIVITY,true );
           mActiveDefaultNetwork= -1;
           if(!mIcsExt .isUserPrompt()) {
                isFailover = tryFailover(prevNetType);
               if(mActiveDefaultNetwork != -1) {
                    NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork ].getNetworkInfo();
                    intent.putExtra(ConnectivityManager. EXTRA_OTHER_NETWORK_INFO, switchTo);
                } else{
                   mDefaultInetConditionPublished= 0;// we're not connected anymore
                    intent.putExtra(ConnectivityManager. EXTRA_NO_CONNECTIVITY,true );
                }
            }
        }
       /** M: @} */
    }
    intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
   if(FeatureOption.MTK_GEMINI_SUPPORT) {
       if(ConnectivityManager.isRadioNumValid(simId)) {
            intent.putExtra(ConnectivityManager. EXTRA_SIM_ID,simId);
        }
    }
   // Reset interface if no other connections are using the same interface
   booleandoReset =true;
    LinkProperties linkProperties = mNetTrackers[prevNetType].getLinkProperties();
   if(linkProperties !=null) {
        String oldIface = linkProperties.getInterfaceName();
       if(TextUtils.isEmpty(oldIface) == false) {
           for(NetworkStateTracker networkStateTracker :mNetTrackers) {
               if(networkStateTracker ==null)continue;
                NetworkInfo networkInfo = networkStateTracker.getNetworkInfo();
               if(networkInfo.isConnected() && networkInfo.getType() != prevNetType) {
                    LinkProperties l = networkStateTracker.getLinkProperties();
                   if(l ==null)continue;
                   if(oldIface.equals(l.getInterfaceName())) {
                        doReset = false;
                       break;
                    }
                }
            }
        }
    }

   // do this before we broadcast the change
    handleConnectivityChange(prevNetType, doReset);

   finalIntent immediateIntent =newIntent(intent);
    immediateIntent.setAction( CONNECTIVITY_ACTION_IMMEDIATE );
    sendStickyBroadcast(immediateIntent);
     sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay());
   /*
     * If the failover network is already connected, then immediately send
     * out a followup broadcast indicating successful failover
     */
   if(mActiveDefaultNetwork != -1) {
        sendConnectedBroadcastDelayed( mNetTrackers[mActiveDefaultNetwork ].getNetworkInfo(),
                getConnectivityChangeDelay());
    }

   /* whenever any interface is down, try to restore default */
   if(FeatureOption.MTK_DT_SUPPORT !=true)
    {
       if(!isFailover) {
            tryRestoreDefault();
        }
    }
}
pivate void handleConnect(NetworkInfo info) {
   finalintnewNetType = info.getType();

    setupDataActivityTracking(newNetType);

   // snapshot isFailover, because sendConnectedBroadcast() resets it
   booleanisFailover = info.isFailover();
   finalNetworkStateTracker thisNet =mNetTrackers [newNetType];
   finalString thisIface = thisNet.getLinkProperties().getInterfaceName();

   // if this is a default net and other default is running
   // kill the one not preferred
   if(mNetConfigs [newNetType].isDefault()) {//是否是默認網絡
       if(mActiveDefaultNetwork != -1 &&mActiveDefaultNetwork!= newNetType) {
           if(isNewNetTypePreferredOverCurrentNetType(newNetType)) {//網絡優先級判斷,wifi開啓的情況下,數據網絡會在這裏通過 tearDown關掉
               // tear down the other
                NetworkStateTracker otherNet =
                       mNetTrackers[mActiveDefaultNetwork ];
               if(DBG ) {
                    log("Policy requires "+ otherNet.getNetworkInfo().getTypeName() +
                       " teardown");
                }
               if(!teardown(otherNet)) {
                    loge("Network declined teardown request");
                   //MTK mark
                    Xlog.e(MTK_TAG, "Since we may teardown it by other way, just go on" );
                   //teardown (thisNet);
                   //return;
                }
            } else{
                  // don't accept this one
                   if(VDBG ) {
                        log("Not broadcasting CONNECT_ACTION "+
                           "to torn down network " + info.getTypeName());
                    }
                    teardown(thisNet);
                   return;
            }
        }
       synchronized(ConnectivityService.this) {
           // have a new default network, release the transition wakelock in a second
           // if it's held.  The second pause is to allow apps to reconnect over the
           // new network
           if(mNetTransitionWakeLock .isHeld()) {
               mHandler.sendMessageDelayed(mHandler .obtainMessage(
                       EVENT_CLEAR_NET_TRANSITION_WAKELOCK ,
                       mNetTransitionWakeLockSerialNumber , 0),
                        1000);
            }
        }
       mActiveDefaultNetwork= newNetType;
       // this will cause us to come up initially as unconnected and switching
       // to connected after our normal pause unless somebody reports us as reall
       // disconnected
       mDefaultInetConditionPublished= 0;
       mDefaultConnectionSequence++;
       mInetConditionChangeInFlight=false ;
       // Don't do this - if we never sign in stay, grey
       //reportNetworkCondition(mActiveDefaultNetwork, 100);
    }
    thisNet.setTeardownRequested( false);
    updateNetworkSettings(thisNet);
    handleConnectivityChange(newNetType, false);
    sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());

   // notify battery stats service about this network
   finalString iface = thisNet.getLinkProperties().getInterfaceName();
   if(iface !=null) {
       try{
            BatteryStatsService. getService().noteNetworkInterfaceType(iface, newNetType);
        } catch(RemoteException e) {
           // ignored; service lives in system_server
        }
    }
}  
--------------------------------------------------------------
 private void sendConnectedBroadcastDelayed(NetworkInfo info, intdelayMs) {
        sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE );
        sendGeneralBroadcastDelayed(info, CONNECTIVITY_ACTION, delayMs);
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章