天天看點

android 系統資料業務---模式4 資料業務模式

4 資料業務模式

在手機以及子產品中,移動/聯通/電信的信号都會有類似下面的2G/3G/4G切換,

android 系統資料業務---模式4 資料業務模式

       圖一 信号模式切換圖

這些值的定義都在RILConstants.java中,如下,

/* NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE */
int NETWORK_MODE_WCDMA_PREF = 0; /* GSM/WCDMA (WCDMA preferred) */
int NETWORK_MODE_GSM_ONLY   = 1; /* GSM only */
int NETWORK_MODE_WCDMA_ONLY  = 2; /* WCDMA only */
int NETWORK_MODE_GSM_UMTS   = 3; /* GSM/WCDMA (auto mode, according to PRL)
int NETWORK_MODE_CDMA       = 4; /* CDMA and EvDo (auto mode, according to PRL)
int NETWORK_MODE_CDMA_NO_EVDO   = 5; /* CDMA only */
int NETWORK_MODE_EVDO_NO_CDMA   = 6; /* EvDo only */
int NETWORK_MODE_GLOBAL   = 7; /* GSM/WCDMA, CDMA, and EvDo*/                                            
int NETWORK_MODE_LTE_CDMA_EVDO  = 8; /* LTE, CDMA and EvDo */
int NETWORK_MODE_LTE_GSM_WCDMA  = 9; /* LTE, GSM/WCDMA */
int NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA = 10;
/* LTE, CDMA, EvDo, GSM/WCDMA */
int NETWORK_MODE_LTE_ONLY     = 11; /* LTE Only mode. */
int NETWORK_MODE_LTE_WCDMA  = 12; /* LTE/WCDMA */
           

當然,ril庫中也會有對應值的定義。

2.1 資料網絡模式預設值

在切換信号之前,首先看看android系統中信号的預設值。在加載完系統的SIM卡之後,然後才會設定信号的預設值。

主要流程圖如下,

android 系統資料業務---模式4 資料業務模式

                                                   圖二 擷取資料網絡預設值流程圖

該流程圖分為2個程序,左半部分為系統服務所在的程序,又半部分為phone程序。

主要的步驟如下,

1,android系統啟動加載sim卡完成之後,發送ACTION_INTERNAL_SIM_STATE_CHANGED廣播;

2, 系統服務所在的程序的SubscriptionInfoUpdater的構造方法中會注冊該廣播, sReceiver對該廣播的處理如下,

else if (action.equals(IccCardProxy.ACTION_INTERNAL_SIM_STATE_CHANGED)) {
  if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(simStatus)) {//sim被鎖
         String reason = intent.getStringExtra(
                        IccCardConstants.INTENT_KEY_LOCKED_REASON);
         sendMessage(obtainMessage(EVENT_SIM_LOCKED, slotId, -1, reason));
  } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(simStatus)){//sim加載完
          sendMessage(obtainMessage(EVENT_SIM_LOADED, slotId, -1));//發送消息
  }
           

3, 系統服務所在的程序處理完成之後,通過binder機制跨程序調用phone程序設定資料網絡預設sim卡以及信号值。

PhoneFactory的calculatePreferredNetworkType方法如下,

public static int calculatePreferredNetworkType(Context context, int phoneSubId) {
int networkType = android.provider.Settings.Global.getInt(context.getContentResolver(),
         android.provider.Settings.Global.PREFERRED_NETWORK_MODE + phoneSubId,
                RILConstants.PREFERRED_NETWORK_MODE);
    return networkType;
}
           

當然,首先讀取setting資料庫中的PREFERRED_NETWORK_MODE 字段值,如果為空就設定RILConstants的

PREFERRED_NETWORK_MODE值。

在剛刷機時,該值肯定為空,隻有在設定之後,信号值才會儲存在PREFERRED_NETWORK_MODE 字段中。

也就是說,如果不是刷機啟動,機器開機後會預設加載上次設定的值。

RILConstants的PREFERRED_NETWORK_MODE值如下,

int PREFERRED_NETWORK_MODE      = TelephonyManager
            .getDefaultPreferredNetworkType(0, NETWORK_MODE_WCDMA_PREF);
           

TelephonyManager的getDefaultPreferredNetworkType方法如下,

public static int getDefaultPreferredNetworkType(int phoneId, int defaultValue) {
        String mode = getTelephonyProperty(phoneId, "ro.telephony.default_network", null);
        if (mode != null) {
            return Integer.parseInt(mode);
        }
        return defaultValue;
    }
           

這2個方法的目的都是為設定資料網絡信号值,

1,首先通過配置檔案設定,android系統中一般都有設定,雖然設定的檔案不同,但是語句完全一樣,

ro.telephony.default_network=5
           

2,如果配置檔案未設定,就會在RILConstants中進行設定, getDefaultPreferredNetworkType方法第二個參數就是預設值。

當然,幾乎所有的android基線都會采用第一種方法進行設定,因為這樣可以根據不同的項目設定不同的配置檔案,靈活度高。

2.2 開機資料網絡設定

一般雙卡手機開機時,會調用三次RIL的setPreferredNetworkType方法向modem發送

RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE消息設定資料網絡。

2.2.1第一次設定

第一次設定比較容易,是在phone程序的RIL和ril守護程序連接配接之後,收到守護程序上報的RIL_UNSOL_RIL_CONNECTED

消息就直接設定網絡制式,

case RIL_UNSOL_RIL_CONNECTED: {
     if (RILJ_LOGD) unsljLogRet(response, ret);
getRadioCapability(mSupportedRafHandler.obtainMessage());
// Initial conditions
           setRadioPower(false, null);
           setPreferredNetworkType(mPreferredNetworkType, null);
           setCdmaSubscriptionSource(mCdmaSubscription, null);
           setCellInfoListRate(Integer.MAX_VALUE, null);
           notifyRegistrantsRilConnectionChanged(((int[])ret)[0]);
           break;
 }
           

mPreferredNetworkType的值是在RIL構造方法中指派的,一般為系統的預設值。

2.2.2第二次設定

其實,第二次和第三次設定的過程完全一樣,都在在SIM加載完設定SIM資訊的時候調用的,間隔時間也很短.幾秒鐘甚至不到 1秒鐘。

都是SubscriptionController裡面的方法,例如setCarrierText, setIconTint, setMccMnc等等。

這些方法都是調用notifySubscriptionInfoChanged方法進行設定的,調用流程圖如下,

android 系統資料業務---模式4 資料業務模式

整個過程比較簡單直白,在TelephonyRegistry和ServiceStateTracker使用了一個簡單的listener,

SstSubscriptionsChangedListener是ServiceStateTracker的内部類,繼承于OnSubscriptionsChangedListener,

并且在ServiceStateTracker調用SubscriptionManager對象的addOnSubscriptionsChangedListener方法注冊的,

最後調用TelephonyRegistry的addOnSubscriptionsChangedListener方法完成注冊。

2.3設定界面的設定過程

圖一 界面對應的代碼為MobileNetworkSettings.java,資料網絡設定的流程圖如下,

android 系統資料業務---模式4 資料業務模式

重點分析以下三個點:

1,MobileNetworkSettings的onPreferenceChange方法,

MobileNetworkSettings的onPreferenceChange方法如下,

public boolean onPreferenceChange(Preference preference, Object objValue) {
   final int phoneSubId = mPhone.getSubId(); //擷取卡槽
   if (preference == mButtonPreferredNetworkMode) {
      //NOTE onPreferenceChange seems to be called even if there is no change
      //Check if the button value is changed from the System.Setting
      mButtonPreferredNetworkMode.setValue((String) objValue);
      int buttonNetworkMode;
      buttonNetworkMode = Integer.valueOf((String) objValue).intValue();
      int settingsNetworkMode = android.provider.Settings.Global.getInt(
          mPhone.getContext().getContentResolver(),
          android.provider.Settings.Global.PREFERRED_NETWORK_MODE + phoneSubId,
                    preferredNetworkMode);//擷取目前的資料網絡模式
      if (buttonNetworkMode != settingsNetworkMode) {
            int modemNetworkMode;
            // if new mode is invalid ignore it
            switch (buttonNetworkMode) {
               case Phone.NT_MODE_WCDMA_PREF:
               case Phone.NT_MODE_GSM_ONLY:
               case Phone.NT_MODE_WCDMA_ONLY:
               case Phone.NT_MODE_GSM_UMTS:
               case Phone.NT_MODE_CDMA:
               case Phone.NT_MODE_CDMA_NO_EVDO:
               case Phone.NT_MODE_EVDO_NO_CDMA:
               case Phone.NT_MODE_GLOBAL:
               case Phone.NT_MODE_LTE_CDMA_AND_EVDO:
               case Phone.NT_MODE_LTE_GSM_WCDMA:
               case Phone.NT_MODE_LTE_CDMA_EVDO_GSM_WCDMA:
               case Phone.NT_MODE_LTE_ONLY:
               case Phone.NT_MODE_LTE_WCDMA:
                  // This is one of the modes we recognize
                  modemNetworkMode = buttonNetworkMode;
                  break;
               default:
                   return true;
       }
android.provider.Settings.Global.putInt(mPhone.getContext().getContentResolver(),
         android.provider.Settings.Global.PREFERRED_NETWORK_MODE + phoneSubId,
           buttonNetworkMode );// 儲存到資料庫中
                //Set the modem network mode
 mPhone.setPreferredNetworkType(modemNetworkMode, mHandler
        .obtainMessage(MyHandler.MESSAGE_SET_PREFERRED_NETWORK_TYPE));
     }
}
           

由此可見,主要步驟如下,

A,首先從資料庫中擷取上次的信号模式,如果和目前的值相等就沒有設定的必要;

B,然後檢查模式是否正确,将模式的值儲存在設定資料庫中;

C,調用PhoneProxy的setPreferredNetworkType方法設定網絡模式。

其中需要注意的是MESSAGE_SET_PREFERRED_NETWORK_TYPE這個消息。

2.4 TelephonyManager設定

TelephonyManager是有phone程序有關的API接口,當然也可以進行網絡設定,調用其setPreferredNetworkType方法就可以了,

當然需要添加MODIFY_PHONE_STATE權限,

調用流程圖如下,

android 系統資料業務---模式4 資料業務模式

整個過程和資料業務的打開調用過程差不多。

TelephonyManager的 setPreferredNetworkType方法如下,

try {
    return getITelephony().setPreferredNetworkType(networkType);
}
           

跨程序調用phone程序的PhoneInterfaceManager的setPreferredNetworkType方法,如下,

首先檢查權限,

enforceModifyPermissionOrCarrierPrivilege();
           

然後發送CMD_SET_PREFERRED_NETWORK_TYPE消息切換到主線程中執行,

Boolean success = (Boolean) sendRequest(CMD_SET_PREFERRED_NETWORK_TYPE, networkType, subId);
           

如果切換成功,将切換後的值儲存到資料庫,

if (success) {
     Settings.Global.putInt(mPhone.getContext().getContentResolver(),
               Settings.Global.PREFERRED_NETWORK_MODE + subId, networkType);
}
           

PhoneInterfaceManager對CMD_SET_PREFERRED_NETWORK_TYPE消息處理如下,

request = (MainThreadRequest) msg.obj;
onCompleted = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE_DONE, request);
int networkType = (Integer) request.argument;
getPhoneFromRequest(request).setPreferredNetworkType(networkType, onCompleted);
break;
           

首先封裝EVENT_SET_PREFERRED_NETWORK_TYPE_DONE消息,

然後調用getPhoneFromRequest擷取實際的phone對象,當然哪個對象都繼承于PhoneBase,

最後的setPreferredNetworkType在PhoneBase中實作,

PhoneBase直接調用RIL的setPreferredNetworkType方法進行設定。

mCi.setPreferredNetworkType(networkType, response);
           

最後注意,當RIL收到modem的處理消息時,會向PhoneInterfaceManager發送已經封裝的

EVENT_SET_PREFERRED_NETWORK_TYPE_DONE消息。回調處理在此就不論述了。