1. 程式人生 > >android 系統資料業務---模式切換分析(下)

android 系統資料業務---模式切換分析(下)

5.3 RIL_REQUEST_DATA_REGISTRATION_STATE

在GsmServiceStateTracker的構造方法中,註冊了一些監聽事件,

mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
mCi.registerForVoiceNetworkStateChanged(this,EVENT_NETWORK_STATE_CHANGED, null);

當ril守護程序上報一些訊息時,例如UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,就會發送

EVENT_NETWORK_STATE_CHANGED訊息, GsmServiceStateTracker對該訊息處理如下,

case EVENT_NETWORK_STATE_CHANGED:
     pollState();
   break;

5.3.1 訊息傳送

以電信卡為例,在資料網路模式切換的過程中,都會呼叫GsmServiceStateTracker的pollState方法獲取模式切換之前的狀態,

mPollingContext[0]++;
   mCi.getDataRegistrationState(
   obtainMessage(EVENT_POLL_STATE_GPRS, mPollingContext));

一會兒處理訊息回撥時會呼叫該類對EVENT_POLL_STATE_GPRS訊息的處理,

RIL中的getDataRegistrationState方法如下,

@Override
public void getDataRegistrationState (Message result) {
    //訊息封裝
   RILRequest rr
           = RILRequest.obtain(RIL_REQUEST_DATA_REGISTRATION_STATE, result);
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
send(rr);//通過socket向的ril傳送 RIL_REQUEST_DATA_REGISTRATION_STATE
    }

3.3.2 訊息回撥處理

RIL中對RIL_REQUEST_DATA_REGISTRATION_STATE訊息處理如下,

首先呼叫responseStrings方法獲取返回的資料,

case RIL_REQUEST_DATA_REGISTRATION_STATE: ret =  responseStrings(p); break;

然後回撥GsmServiceStateTracker到進行處理,

if (rr.mResult != null) {
     AsyncResult.forMessage(rr.mResult, ret, null);
        rr.mResult.sendToTarget();
}

GsmServiceStateTracker的handleMessage方法對EVENT_POLL_STATE_GPRS訊息處理如下,

1,首先資料模式的CS/PS值,然後儲存在ServiceState物件中,

states = (String[])ar.result;//獲取上報的結果

int type = 0;
int regState = ServiceState.RIL_REG_STATE_UNKNOWN;
mNewReasonDataDenied = -1;
mNewMaxDataCalls = 1;
if (states.length > 0) { //根據字串組的長度解析CS/PS值,一般在長度為4
   try {
      regState = Integer.parseInt(states[0]);//獲取CS
// states[3] (if present) is the current radio technology
      if (states.length >= 4 && states[3] != null) { //獲取PS
          type = Integer.parseInt(states[3]);
      }
      if ((states.length >= 5 ) && (regState == ServiceState.RIL_REG_STATE_DENIED)) {
           mNewReasonDataDenied = Integer.parseInt(states[4]);
      }
      if (states.length >= 6) {
          mNewMaxDataCalls = Integer.parseInt(states[5]);
      }
   } catch (NumberFormatException ex) {
    loge("error parsing GprsRegistrationState: " + ex);
}
}
// 將CS/PS值儲存在ServiceState物件中
int dataRegState = regCodeToServiceState(regState); 
mNewSS.setDataRegState(dataRegState);
mDataRoaming = regCodeIsRoaming(regState);
mNewSS.setRilDataRadioTechnology(type);

2,呼叫pollStateDone方法發起撥號上網.

pollStateDone方法中有關撥號上網的程式碼如下,

 //對比上次和當前的網路資料模式的CS值
boolean hasDataRegStateChanged =mSS.getDataRegState() != mNewSS.getDataRegState();
 //對比上次和當前的網路資料模式的PS值
boolean hasRilDataRadioTechnologyChanged =
     mSS.getRilDataRadioTechnology() != mNewSS.getRilDataRadioTechnology();
if (hasDataRegStateChanged || hasRilDataRadioTechnologyChanged) {
     notifyDataRegStateRilRadioTechnologyChanged();
     mPhone.notifyDataConnection(null);
 }

如果上次和當前的CS/PS值有一個不相同,則會呼叫notifyDataRegStateRilRadioTechnologyChanged方法,

最後呼叫RIL的setupDataCall方法向ril庫傳送RIL_REQUEST_SETUP_DATA_CALL訊息進行撥號上網。

5.4 RIL_REQUEST_SETUP_DATA_CALL

上層發起撥號一般會呼叫RIL向ril守護程序傳送RIL_REQUEST_SETUP_DATA_CALL訊息。

繼續上個小節, GsmServiceStateTracker的notifyDataRegStateRilRadioTechnologyChanged方法其實在父類

ServiceStateTracker中實現,如下,

protected void notifyDataRegStateRilRadioTechnologyChanged() {
   int rat = mSS.getRilDataRadioTechnology();
   int drs = mSS.getDataRegState();
   if (DBG) log("notifyDataRegStateRilRadioTechnologyChanged: drs=" + drs + " rat=" + rat);
 mPhoneBase.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
                ServiceState.rilRadioTechnologyToString(rat));
  mDataRegStateOrRatChangedRegistrants.notifyResult(new Pair<Integer, Integer>(drs, rat));
}

mDataRegStateOrRatChangedRegistrants.notifyResult這句話怎麼繼續呼叫呢?

mDataRegStateOrRatChangedRegistrants其實也是RegistrantList物件,

protected RegistrantList mDataRegStateOrRatChangedRegistrants = new RegistrantList();

關鍵是看誰註冊,誰註冊就是誰呼叫,註冊方法如下,

public void registerForDataRegStateOrRatChanged(Handler h, int what, Object obj) {
    Registrant r = new Registrant(h, what, obj);
    mDataRegStateOrRatChangedRegistrants.add(r);
    notifyDataRegStateRilRadioTechnologyChanged();
}

整個android系統中有2個地方呼叫了該方法, DcTracker.java和DataConnection.java,

首先看看DataConnection,在DataConnection的內部類DcDefaultState的enter方法中,

mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(getHandler(),                  
DataConnection.EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED, null);

mDataRegStateOrRatChangedRegistrants.notifyResult這句話其實就是向DataConnection傳送

EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED訊息。

這裡還有一個需要注意的點是DcDefaultState狀態機是DataConnection其他所有狀態機的父狀態機,

但不是父類,這是有區別的,雖然功能是類似於父類。

然後看DcTracker.java,DcTracker.java的構造方法會呼叫update方法, update 方法呼叫registerForAllEvents方法,

該方法中有關注冊的程式碼如下,

mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(this,
                DctConstants.EVENT_DATA_RAT_CHANGED, null);

同樣的, mDataRegStateOrRatChangedRegistrants.notifyResult也向DcTracker.java傳送了EVENT_DATA_RAT_CHANGED訊息, 

DcTracker.java的handleMessage對該訊息處理如下,

case DctConstants.EVENT_DATA_RAT_CHANGED:
    //May new Network allow setupData, so try it here
     setupDataOnConnectableApns(Phone.REASON_NW_TYPE_CHANGED,
           RetryFailures.ONLY_ON_CHANGE);
break;

setupDataOnConnectableApns處理流程詳情見第二章開頭,其後的過程和開啟資料業務的流程完全一摸一樣。將步驟再列一下,

1,建立DataConnection 和 DcAsyncChannel物件, 將2個物件通過Handler繫結,通過AsyncChannel機制進行程序間的通訊。

2,向RIL傳送RIL_REQUEST_SETUP_DATA_CALL訊息,進行撥號

3,完成狀態從DcInactiveState 到 DcActivatingState 最後到 DcActiveState的轉變

4,構造ConnectivityService 物件,註冊。ConnectivityService將通過AsyncChannel與phone程序的NetworkAgent進行跨程序通訊。

5,通過NetworkManagementService和netd守護程序進行互動,完成完成網路屬性的新增,這樣才算完成了撥號上網。

並且,每一次資料網路的切換,ril庫會上報RIL_UNSOL_DATA_CALL_LIST_CHANGED訊息,沒有上報或者上報的資料不對肯定是無法上網的;

每一次資料網路的切換,AP測會主動查詢註冊狀態,ril庫會返回RIL_REQUEST_DATA_REGISTRATION_STATE資訊以及資料網路的註冊狀態,

返回的資訊時一個數組,比較重要的是第一個和第四個,如果這2個值有問題,就無法進行撥號上網。

小結:

其實,資料業務的切換包括了資料業務關閉和開啟,和ril守護程序互動的流程如下,

1,phone程序傳送RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE訊息到ril守護程序。

2,ril守護程序首先斷開網路,上報RIL_UNSOL_DATA_CALL_LIST_CHANGED訊息。

3,phone程序更新NetworkAgent 網路狀態,和netd守護程序互動。

4, ril守護程序上報大量訊息,例如UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED訊息等。

5,phone程序傳送RIL_REQUEST_DATA_REGISTRATION_STATE訊息查詢網路註冊狀態。

6, phone程序根據ril守護程序迴應的RIL_REQUEST_DATA_REGISTRATION_STATE訊息向ril守護程序傳送RIL_REQUEST_SETUP_DATA_CALL訊息發起撥號。

7,phone程序會收到RIL_UNSOL_DATA_CALL_LIST_CHANGED訊息更新狀態等。