主要介绍ServiceStateTracker对ServiceState管理的机制和流程
IMSI(International Mobile Subscriber Identification Number,国际移动用户识别码)
ServiceState:保存SIM卡注册成功后电信运行商网络的一些基本服务信息,关键信息包括:电信运行商编号、Radio无线通信模块使用的技术类型和状态、电信运营商网络是否处于漫游状态、无线网络信号强度等电信服务基本信息;ServiceState服务状态的管理和更新是通过ServiceStateTracker对象完成的,主要维护ServiceState类的ss和newSS两个实体对象,从而完成ServiceState服务状态的管理和更新。
一、ServiceState实体类的关键信息:
1.类的实质
ServiceState类实现了Parcelable[可以了解下原理]接口, 主要有以下两个过程组成:
writeToParcel序列化过程,将对象数据写入外部提供的Parcel中;
createFromParcel反序列化过程,通过外部提供的Parcel获取基本数据来创建数据对象。
2.类的关键常量及属性
ServiceState类的关键常量主要是管理和保存4种服务状态和一些无线通信模块的标准技术。无线通信网络类型覆盖GSM、CDMA和UMTS等全球主流的无线通信技术。
ServiceState类的关键属性定义如下:(Android7.0)
private int mVoiceRegState = STATE_OUT_OF_SERVICE;
private int mDataRegState = STATE_OUT_OF_SERVICE; // 服务状态,0~3共4种状态可选,默认取值为1。
private int mVoiceRoamingType;
private int mDataRoamingType; // 是否进入漫游网络标志
private String mVoiceOperatorAlphaLong; // 电信运营商名称(完整)
private String mVoiceOperatorAlphaShort; // 电信运营商名称(简写)
private String mVoiceOperatorNumeric; // 电信运营商编号
private String mDataOperatorAlphaLong;
private String mDataOperatorAlphaShort;
private String mDataOperatorNumeric;
private boolean mIsManualNetworkSelection; // 手动选择电信运营商标志
private boolean mIsEmergencyOnly; // 仅紧急呼叫标志
3.类的关键方法
主要体现在以下三个方面:
二、ServiceStateTracker的运行机制:
android.telephony包路径下定义了ServiceState和SignalStrength两个实体类,这两个类不用区分GSM/CDMA手机网络制式类型;CellLocation抽象类定义在android.telephony包路径下,而在子包gsm和cdma下分别实现了GsmCellLocation和CdmaCellLocation类;com.android.internal.telephony包路径下定义ServiceStateTracker抽象类,同时在子包gsm和cdma下分别继承和实现了GsmServiceStateTracker和CdmaServiceStateTracker类。
ServiceStateTracker类与CallTracker相同,共同继承了Handle类,其实质是自定义的Handle消息处理类,主要两方面的处理逻辑:
1.ServiceStateTracker代码结构:
关键属性:
private CommandsInterface mCi; // RIL的Java对象,此对象与GSMPhone对象一样,mCi对象具备与RIL层交互的能力
public ServiceState mSS;
private ServiceState mNewSS;
private SignalStrength mSignalStrength; // 保存手机接入电信运营商无线网络后的信号量
public CellLocation mCellLoc; // 小区信息,国内电信运营商基本没有使用
public CellLocation mNewCellLoc;
private GsmCdmaPhone mPhone; // GSMPhone对象
关键方法:
由以上可知,ServiceStateTracker对象主要通过更新mSS和mSignalStrength对象来完成服务信息的更新。对于服务状态的控制,Phone对外提供统一的方法,最终通过调用mSST对象响应的方法来实现,及ServiceStateTracker对象。
2.ServiceStateTracker的Handler消息处理机制
Handler有三种处理方式,在ServiceStateTracker类中使用其中两种运行和处理机制:
1).基本的Handler消息注册和响应处理机制
在ServiceStateTracker类的构造方法中找到Handler消息注册的代码逻辑,GsmServiceStateTracker对象会被动接收并相应RIL对象发出的7种类型的Handler消息,最关键的是以下5钟:
EVENT_RADIO_AVAILABLE(无线通信模块Modem或Radio开启状态)
EVENT_RADIO_STATE_CHANGED(无线通信模块状态变化)
EVENT_NETWORK_STATE_CHANGED(无线网络状态变化)
EVENT_SIGNAL_STRENGTH_UPDATE(无线网络信号量变化)
EVENT_SIM_READY(手机中的SIM卡已经准备完成)
[这几种服务状态变化的Handler消息都定义在ServiceStateTracker抽象类中,并且仅在该类中产生相应,也就是说,有且仅有ServiceStateTracker对象会接收和响应RIL对象发出的这几种与网络服务状态相关的Handler消息通知。]
对上面5种Handler消息的响应在handleMessage方法中。处理如下:
case EVENT_RADIO_AVAILABLE: // Radio状态可用,没有处理逻辑
break;
case EVENT_SIM_READY:
......
pollState();
queueNextSignalStrengthPoll(); [1]
break;
case EVENT_RADIO_STATE_CHANGED:
......
pollState();
break;
case EVENT_NETWORK_STATE_CHANGED:
pollState();
break;
case EVENT_GET_SIGNAL_STRENGTH:
......
onSignalStrengthResult(ar); // 响应接入的无线网络信号量变化
queueNextSignalStrengthPoll();
break;
pollState():查询当前最新网络服务状态,其逻辑主要分为两个部分:
通过mCi.getRadioState()判断Riadio无线通信模块是否正常:
switch (mCi.getRadioState()) {
case RADIO_UNAVAILABLE:
mNewSS.setStateOutOfService(); // STATE_OUT_OF_SERVICE
mNewCellLoc.setStateInvalid(); // 设置小区广播不可用
setSignalStrengthDefaultValues(); //设置无线信号量为默认值
mGotCountryCode = false; // 未获取国家代码
pollStateDone();
break;
case RADIO_OFF:
mNewSS.setStateOff();
mNewCellLoc.setStateInvalid();
setSignalStrengthDefaultValues();
mGotCountryCode = false;
pollStateDone();
break;
default: // 正常
mCi.getOperator(obtainMessage(EVENT_POLL_STATE_OPERATOR, mPollingContext));// 获取注册的运营商网络信息
mCi.getDataRegistrationState(obtainMessage(EVENT_POLL_STATE_GPRS, mPollingContext)); // 获取注册的数据连接类型
mCi.getVoiceRegistrationState(obtainMessage(EVENT_POLL_STATE_REGISTRATION, mPollingContext));// 获取注册的语音通话网络类型
mCi.getNetworkSelectionMode(obtainMessage(EVENT_POLL_STATE_NETWORK_SELECTION_MODE, mPollingContext));// 获取网络类型
break;
}
2).Handler消息Callback回调处理方式
这种Handler消息处理机制的实现逻辑代码框架基本一致,主要分为两步完成:
(1)调用ObtainMessage方法创建Message对象;
(2)通过mCi对象向RIL对象发起网络服务信息查询方法的调用
case EVENT_POLL_STATE_REGISTRATION:
case EVENT_POLL_STATE_GPRS:
case EVENT_POLL_STATE_OPERATOR:
case EVENT_POLL_STATE_NETWORK_SELECTION_MODE:
ar = (AsyncResult) msg.obj;
handlePollStateResult(msg.what, ar);
break;
ServiceStateTracker与RIL对象的交互根据这两个对象谁主动发起分为两大类:
1)ServiceStateTracker对象被动接收:ServiceStateTracker对象的消息处理机制,它会被动的接收和处理RIL对象上报的7个类型的Handle消息。
2)ServiceStateTracker对象主动发起:最重要的是调用setRadioPower方法打开或关闭Radio无线通信模块。
3.handlePollStateResult方法处理逻辑
其处理逻辑可以分为三部分,分别如下:
1)RIL返回查询结果的异常判断和处理
// Ignore stale requests from last poll
if (ar.userObj != mPollingContext) return; // 请求与返回的消息不匹配,直接返回不处理
if (ar.exception != null)
{ // RIL对象返回Message对象,其中产生了异常
CommandException.Error err = null;
if (ar.exception instanceof CommandException) {
err = ((CommandException) (ar.exception)).getCommandError();
}
if (err == CommandException.Error.RADIO_NOT_AVAILABLE) {
// Radio has crashed or turned off
cancelPollState();
loge("handlePollStateResult cancelPollState due to RADIO_NOT_AVAILABLE");
// Clear status and invoke pollStateDone to notify other module
if (mCi.getRadioState() != CommandsInterface.RadioState.RADIO_ON) {
mNewSS.setStateOff();
mNewCellLoc.setStateInvalid();
setSignalStrengthDefaultValues();
mGotCountryCode = false;
pollStateDone();
}
return;
}
}
2)分别处理4个不同网络服务查询返回的结果 handlePollStateResultMessage方法中
case EVENT_POLL_STATE_REGISTRATION: {
if (mPhone.isPhoneTypeGsm()) {
states = (String[]) ar.result; // 获取查询结果基本信息
int regState = ServiceState.RIL_REG_STATE_UNKNOWN;
if (states.length > 0) {
try {
regState = Integer.parseInt(states[0]); // 获取网络注册状态编号
...... // 获取小区广播相关状态信息lac、cid、和psc
} catch (NumberFormatException ex) {
loge("error parsing RegistrationState: " + ex);
}
}
mGsmRoaming = regCodeIsRoaming(regState); // 根据网络注册状态编号获取并设置漫游标志
mNewSS.setVoiceRegState(regCodeToServiceState(regState)); // 根据网络注册状态编号获取并设置服务状态
boolean isVoiceCapable = mPhone.getContext().getResources()
.getBoolean(com.android.internal.R.bool.config_voice_capable);
if ((regState == ServiceState.RIL_REG_STATE_DENIED_EMERGENCY_CALL_ENABLED
|| regState == ServiceState.RIL_REG_STATE_NOT_REG_EMERGENCY_CALL_ENABLED
|| regState == ServiceState.RIL_REG_STATE_SEARCHING_EMERGENCY_CALL_ENABLED
|| regState == ServiceState.RIL_REG_STATE_UNKNOWN_EMERGENCY_CALL_ENABLED)
&& isVoiceCapable) {
mEmergencyOnly = true;
} else {
mEmergencyOnly = false;
}
...... // 处理小区信息的逻辑
}
break;
http://www.3gpp.org/ftp/Specs/html-info/
从上面的网络摘录的关键信息·[实际上好像打不开]
0 not registered, MT is not currently searching a new operator to register to
1 registerede, home network // 本地网络
2 not registered, but MT is currently searching a new operator to register to
3 registration denied
4 unknow (e.g. out of GERAN/UTRAN/E-UTRAN coverage)
5 registered, roaming // 漫游网络
6 registered for "SMS only", home network (applicable only when
7 registered for "SMS only", roaming (applicable only when regCodeToServiceState与regCodeIsRoaming与EVENT_POLL_STATE_REGISTRATION保持一致 3)调用pollStateDone方法完成收尾工作 pollStateDone主要分为三个处理逻辑: (1)通过当前状态和新的状态获取服务信息改变的标志 这写服务状态信息变化的标志都是通过ServiceStateTracker对象中多个XX与newXX属性做比较得出的。 (2)更新对象信息 。。。一些变量的更新,不做说明 (3)发出网络服务状态信息变化的消息通知 发出SPN_STRINGS_UPDATED_ACTION广播,更新SPN的显示,设置运营商参数,通过phone对象的方法调用,发出ServiceState变化的通知 三、ServiceState最佳实践与飞行模式的实现 手机成功注册并接入运营商网络后,一般情况下会在home界面显示运营商名称,运营商名称主要有以下两种: 重点可分析updateSpnDisplay()方法,其发出的SPN_STRINGS_UPDATED_ACTION的系统广播,主要有三个定义的Broadcast广播接收过滤器会接收此广播,分别是: 2.通知栏手机信号实时变化 手机信号的实时变化准确说是准实时变化,是由ServiceStateTracker对象调用queueNextSignalStrengthPoll定时向RIL对象发起查询手机接入无线网络的信号量,然后发起信号量变化的通知。 queueNextSignalStrengthPoll代码如下: 3.飞行模式的实现 飞行模式打开或关闭都是通过发送广播Intent.ACTION_AIRPLANE_MODE_CHANGED,广播接收端的处理:主要是通过Phone对象调用setRadioPower方法 case EVENT_POLL_STATE_GPRS: {
if (mPhone.isPhoneTypeGsm()) {
states = (String[]) ar.result;
int type = 0; // 数据连接的类型
int regState = ServiceState.RIL_REG_STATE_UNKNOWN; // 服务状态编号
mNewReasonDataDenied = -1;
mNewMaxDataCalls = 1; // 最大支持的数据连接
if (states.length > 0) {
try {
...... // type、mNewReasonDataDenied和mNewMaxDataCalls变量取值
} catch (NumberFormatException ex) {
loge("error parsing GprsRegistrationState: " + ex);
}
}
int dataRegState = regCodeToServiceState(regState);
mNewSS.setRilDataRegState(regState);
mNewSS.setDataRegState(dataRegState);
mDataRoaming = regCodeIsRoaming(regState);
mNewSS.setRilDataRadioTechnology(type);
//carrier aggregation
mNewSS.setProprietaryDataRadioTechnology(type);
//mNewSS.setRilDataRadioTechnology(type);
}
break;
case EVENT_POLL_STATE_OPERATOR: {
if (mPhone.isPhoneTypeGsm()) {
String opNames[] = (String[]) ar.result;
if (opNames != null && opNames.length >= 3) {
String brandOverride = mUiccController.getUiccCard(getPhoneId()) != null ?
mUiccController.getUiccCard(getPhoneId()).getOperatorBrandOverride() : null;
if (brandOverride != null) {
log("EVENT_POLL_STATE_OPERATOR: use brandOverride=" + brandOverride);
mNewSS.setOperatorName(brandOverride, brandOverride, opNames[2]);
}
}
}
break;
case EVENT_POLL_STATE_NETWORK_SELECTION_MODE: {
ints = (int[])ar.result;
mNewSS.setIsManualSelection(ints[0] == 1); // 设置选择网络类型手动还是自动
if ((ints[0] == 1) && (!mPhone.isManualNetSelAllowed())) {
mPhone.setNetworkSelectionModeAutomatic (null);
}
break;
1.获取运营商信息
handleMessage的响应如下:
private void queueNextSignalStrengthPoll() {
if (mDontPollSignalStrength) {
return;
}
Message msg;
msg = obtainMessage();
msg.what = EVENT_POLL_SIGNAL_STRENGTH;
// TODO Don't poll signal strength if screen is off
sendMessageDelayed(msg, POLL_PERIOD_MILLIS);
}
查询完成后,响应如下:
case EVENT_POLL_SIGNAL_STRENGTH:
// Just poll signal strength...not part of pollState()
if (mPhone.isPhoneTypeGsm()) {
log("handle EVENT_POLL_SIGNAL_STRENGTH GSM " + mDontPollSignalStrength);
if (mDontPollSignalStrength) {
// The radio is telling us about signal strength changes
// we don't have to ask it
return;
}
}
mCi.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH));//向RIL对象查询最新的网络信号量,obtainMessage穿件查询信号量成功后的callback消息对象
break;
case EVENT_GET_SIGNAL_STRENGTH:
if (!(mCi.getRadioState().isOn())) {
// Polling will continue when radio turns back on
return;
}
ar = (AsyncResult) msg.obj;
onSignalStrengthResult(ar); // 保存和更新无线网络信号量
queueNextSignalStrengthPoll(); // 循环调用该方法
break;