4 資料業務模式
在手機以及子產品中,移動/聯通/電信的信号都會有類似下面的2G/3G/4G切換,
圖一 信号模式切換圖
這些值的定義都在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卡之後,然後才會設定信号的預設值。
主要流程圖如下,
圖二 擷取資料網絡預設值流程圖
該流程圖分為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方法進行設定的,調用流程圖如下,
整個過程比較簡單直白,在TelephonyRegistry和ServiceStateTracker使用了一個簡單的listener,
SstSubscriptionsChangedListener是ServiceStateTracker的内部類,繼承于OnSubscriptionsChangedListener,
并且在ServiceStateTracker調用SubscriptionManager對象的addOnSubscriptionsChangedListener方法注冊的,
最後調用TelephonyRegistry的addOnSubscriptionsChangedListener方法完成注冊。
2.3設定界面的設定過程
圖一 界面對應的代碼為MobileNetworkSettings.java,資料網絡設定的流程圖如下,
重點分析以下三個點:
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權限,
調用流程圖如下,
整個過程和資料業務的打開調用過程差不多。
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消息。回調處理在此就不論述了。