一、前言
手机插入SIM卡并成功启动后,BP Modem会读取SIM卡中的IMSI(International Mobile Subscriber Identification Number,国际移动用户识别码)信息完成SIM卡中信息的验证和电信运营商移动网络的注册,这样手机才能使用电信运营商提供的网络服务,如接打电话、发送接收短彩信、手机上网等服务
二、ServiceStateTracker介绍
在Telephony Frameworks框架层中,ServiceStateTracker对象主要管理网络服务的基本信息,有着非常重要的作用。
ServiceStateTracker抽象类与CallTracker相同,共继承了Handler类,其实质是自定义的Handler消息处理类
GsmServiceStateTracker和CdmaServiceStateTracker分别继承和实现了ServiceStateTracker
三、ServiceStateTracker到RIL流程
GsmServiceStateTracker在构造方法中会注册Handler消息,该类在上次视频中PhoneGloabas初始化构建Phone对象时执行
// frameworks\opt\telephony\src\java\com\android\internal\telephony\gsm\GsmServiceStateTracker.java
public GsmServiceStateTracker(GSMPhone phone) {
// Handler消息注册
mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
mCi.registerForVoiceNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED, null);
mCi.setOnNITZTime(this, EVENT_NITZ_TIME, null);
mCi.setOnRestrictedStateChanged(this, EVENT_RESTRICTED_STATE_CHANGED, null);
mCi.registerForPSStateChanged(this,EVENT_PS_STATE_CHANGED, null);
}
- 在
GsmServiceStateTracker的构造方法中,通过registerForXXX()和setOnXXX()完成不同的Handler消息注册 - 手机启动完成并成功注册网络后,
RIL层会发出EVENT_SIM_READY类型的Handler消息通知,ServiceStateTracker对象调用handleMessage()方法完成此消息的接收,接着调用pollState()方法响应此消息。 - 会在
pollState()方法中向RIL对象发出4个关于网络服务的查询请求,包括- 获取注册的运营商网络信息
- 获取注册的数据连接类型
- 获取注册的语音通话网络类型
- 获取网络类型
RIL完成发起的查询最新网络服务的信息和状态后,通过ServiceStateTracker对象创建的Message对象发起Callback回调,到GsmServiceStateTracker的handleMessage()中去处理,最后到handlePollStateResult(),将查询出来的当前最新的网络服务信息和状态更新和保存在ServiceStateTracker对象的多个属性中。- 所有消息都处理完成后,最后在
pollStateDone()完成处理查询网络服务相关信息结果的收尾工作- 通过当前状态和新的状态获取服务信息改变的标志
- 更新
ss、cellLoc对象信息,同时更新一些gprsState、mMaxDataCalls、mRadioTechnology等属性,此外,重置newSS、newCellLoc等对象的值 - 发出网络服务状态信息变化的消息通知
最终会比对当前的状态和新查询的结果进行比对,当发现不同有变化时,会调用mPhone.notifyXX()向上通知
四、手机状态栏信号实时变化
1. GsmServiceStateTracker处理
在待机界面的状态栏可以观察到手机信号的变化,其实这里的手机信号实时变化,准确来说应该是准实时变化,是由GsmServiceStateTracker对象通过Handler.sendMessageDelay定时向RIL对象发起查询手机接入无线网络的信号量值,然后发起信号量变化通知,通知栏应用收到信号量变化消息通知后,从而更新手机接入的网络信号图标。
首先进入GsmServiceStateTracker.java代码文件,手机开机后,SIM 卡准备完成,RIL层发出 EVENT_SIM_READY通知,GsmServiceStateTracker 对象进入 handleMessage() 方法接收和响应此消息;接着调用当前类的 queueNextSignalStrengthPoll()方法,向RIL对象查询手机信号量,其代码详情如下:
// frameworks\opt\telephony\src\java\com\android\internal\telephony\gsm\GsmServiceStateTracker.java
private void queueNextSignalStrengthPoll() {
...
Message msg;
msg = obtainMessage();
msg.what = EVENT_POLL_SIGNAL_STRENGTH;
// TODO Don't poll signal strength if screen is off
// 延时发送,在ServiceStateTracker定义为20* 1000ms,即20s
sendMessageDelayed(msg, POLL_PERIOD_MILLIS);
}
因为父类ServiceStateTracker也是继承的Handler,因此,20s后会在handleMessage接收并响应该消息:
// frameworks\opt\telephony\src\java\com\android\internal\telephony\gsm\GsmServiceStateTracker.java
case EVENT_POLL_SIGNAL_STRENGTH:
// Just poll signal strength...not part of pollState()
mCi.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH));
break;
RIL完成最新的信号量查询后,通过Callback消息对象发起Handler消息通知,GsmServiceStateTracker对象中的handleMessage()方法会接收和响应此消息通知,处理如下:
// frameworks\opt\telephony\src\java\com\android\internal\telephony\gsm\GsmServiceStateTracker.java
case EVENT_GET_SIGNAL_STRENGTH:
// This callback is called when signal strength is polled
// all by itself
if (!(mCi.getRadioState().isOn())) {
// Polling will continue when radio turns back on
return;
}
ar = (AsyncResult) msg.obj;
onSignalStrengthResult(ar, true);
queueNextSignalStrengthPoll();
break;
接着在onSignalStrengthResult() 根据查询的结果更新和保存最新的信号量相关信息,完成后再次调用queueNextSignalStrengthPoll() 等待下一次查询
# frameworks\opt\telephony\src\java\com\android\internal\telephony\gsm\GsmServiceStateTracker.java
protected boolean onSignalStrengthResult(AsyncResult ar, boolean isGsm) {
SignalStrength oldSignalStrength = mSignalStrength;
// This signal is used for both voice and data radio signal so parse
// all fields
if ((ar.exception == null) && (ar.result != null)) {
mSignalStrength = (SignalStrength) ar.result;
mSignalStrength.validateInput();
mSignalStrength.setGsm(isGsm);
} else {
log("onSignalStrengthResult() Exception from RIL : " + ar.exception);
mSignalStrength = new SignalStrength(isGsm);
}
return notifySignalStrength();
}
![[GsmServiceStateTracker和RIL通信.png]]
手机成功启动并注册到电信运营商网络后,RIL层会发起EVENT_SIM_READY的消息通知,在 GsmServiceStateTracker对象中接收到此消息后,便开始循环调用queueNextSignalStrengthPoll() 方法,将结果通过mCi.get完成手机接入电信运营商网络的无线信号量查询,其流程如上图所示。
2.GsmServiceStateTracker通知给APP
- 从右边看起,
NetworkController是APP SystemUI的一个类,它持有TelephonyManager,调用了listen方法,而TelephonyManager持有ITelephonyRegistry这个接口,调用了它的listen方法
ITelephonyRegistry是一个AIDL文件,用来跨进程通信使用的,TelephonyRegistry实现了它的所有方法,注意到这个类中有个mRecords的ArrayList,用来保存我们的监听对象
-
GsmServiceStateTracker继承了抽象类ServiceStateTracker,GsmServiceStateTracker会收到RIL发过来的信号强度消息,调用父类的notifySignalStrength()方法,ServiceStateTracker持有PhoneBase的对象mPhoneBase,PhoneBase中也有自己的notifySignalStrength方法,并且PhoneBase持有PhoneNotifier接口,而DefaultPhoneNotifier是PhoneNotifier的实现类,会实现notifySignalStrength方法,并且DefaultPhoneNotifier也持有ITelephonyRegistry,调用它的notifySignalStrength(),里面会遍历mRecords这个List,把具体的消息发送给监听者,这样APP就可以收到消息,刷新显示出来了 -
所以其实就是一个通过
aidl进行的跨进程通信,listen负责把监听者添加保存起来,notifyXXX()方法负责把消息通知遍历给所有的监听器的过程
3. 代码分析
1. SystemUI注册网络信号监听的
- 在
NetworkController中的构造方法中,会设置PhoneStateListener监听器,监听从Telephony Framework返回的网络状态变化
// frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
public NetworkController(Context context) {
// telephony
mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
for (int i=0; i < mPhoneCount; i++) {
mPhone.listen(getPhoneStateListener(i),
PhoneStateListener.LISTEN_SERVICE_STATE
| PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
| PhoneStateListener.LISTEN_CALL_STATE
| PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
| PhoneStateListener.LISTEN_DATA_ACTIVITY);
}
}
- 在
TelephonyManager的listen方法中开始监听,可以看到是通过sRegistry继续监听,而sRegistry是通过sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));将IBinder类型的service转化为ITelephonyRegistry类型对象,然后就可以调用ITelephonyRegistry的方法了
public void listen(PhoneStateListener listener, int events) {
String pkgForDebug = mContext != null ? mContext.getPackageName() : "<unknown>";
try {
Boolean notifyNow = true;
/*modify by yuanhaobo for L1860_Req00000163 @ 2014-02-16 begin*/
if (getStandbyCount() > 1) {
if (-1 == listener.mLinkId) {
for (int linkId = 0; linkId < getStandbyCount(); linkId++) {
sRegistry.listenMSMS(pkgForDebug, listener.callback, events, notifyNow, linkId);
}
} else {
sRegistry.listenMSMS(pkgForDebug, listener.callback, events, notifyNow, listener.mLinkId);
}
} else {
sRegistry.listen(pkgForDebug, listener.callback, events, notifyNow);
}
/*modify by yuanhaobo for L1860_Req00000163 @ 2014-02-16 end*/
} catch (RemoteException ex) {
// system process dead
} catch (NullPointerException ex) {
// system process dead
}
}
public TelephonyManager(Context context) {
Context appContext = context.getApplicationContext();
if (appContext != null) {
mContext = appContext;
} else {
mContext = context;
}
if (sRegistry == null) {
sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry"));
}
}
2. ServiceStateTracker通知
ServiceStateTracker.java在onSignalStrengthResult()收到信号消息后,到notifySignalStrength()中
// frameworks/opt/telephony/src/java/com/android/internal/telephony/ServiceStateTracker.java
protected boolean notifySignalStrength() {
boolean notified = false;
synchronized(mCellInfo) {
if (!mSignalStrength.equals(mLastSignalStrength)) {
try {
mPhoneBase.notifySignalStrength();
notified = true;
} catch (NullPointerException ex) {
loge("updateSignalStrength() Phone already destroyed: " + ex
+ "SignalStrength not notified");
}
}
}
return notified;
}
// frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneBase.java
public void notifySignalStrength() {
mNotifier.notifySignalStrength(this);
}
mNotifier 是在PhoneGlobals.java#onCreate() 方法中,在PhoneFactory.java#makeDefaultPhone() 方法产生的
// frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneFactory.java
public static void makeDefaultPhone(Context context) {
sPhoneNotifier = new DefaultPhoneNotifier();
...
int phoneType = TelephonyManager.getPhoneType(networkMode);
if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
Rlog.i(LOG_TAG, "Creating GSMPhone");
sProxyPhone = new PhoneProxy(new GSMPhone(context,
sCommandsInterface, sPhoneNotifier, false, 0), 0);
sProxyPhoneList.add(0, sProxyPhone);
}
sPhoneNotifier在创建Phone时通过新建DefaultPhoneNotifier对象,传入到GSMPhone,也就是PhoneBase中的mNotifier ,在DefaultPhoneNotifier就可以看到notifySignalStrength()方法了,在它的构造方法中可以看到获取了ITelephonyRegistry对象
// frameworks/opt/telephony/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
protected DefaultPhoneNotifier() {
mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry"));
}
@Override
public void notifySignalStrength(Phone sender) {
try {
mRegistry.notifySignalStrength(sender.getSignalStrength(), sender.getLinkID());
} catch (RemoteException ex) {
// system process is dead
}
}
在SystemServer启动时建立了telephonyRegistry对象,并通过ServiceManager添加了进去,之后就可以通过getService()的方式获取到TelephonyRegistry了
// frameworks/base/services/java/com/android/server/SystemServer.java
public void initAndLoop(){
TelephonyRegistry telephonyRegistry = null;
telephonyRegistry = new TelephonyRegistry(context);
ServiceManager.addService("telephony.registry", telephonyRegistry);
}
即调用了TelephonyRegistry中的notifySignalStrength()
// frameworks/base/services/java/com/android/server/TelephonyRegistry.java
public void notifySignalStrength(SignalStrength signalStrength) {
notifySignalStrength(signalStrength, SimRouter.getDefaultPSSim(mContext));
}
public void notifySignalStrength(SignalStrength signalStrength, int linkId) {
if (!checkNotifyPermission("notifySignalStrength()")) {
return;
}
/*merge by yuanhaobo from L1813 @ 2013-11-29 begin*/
synchronized (mRecords) {
mSignalStrength[linkId] = signalStrength;
for (Record r : mRecords) {
if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0)
&& (r.linkId == linkId)) {
try {
r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
}
if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0)
&& (r.linkId == linkId)) {
try {
int gsmSignalStrength = signalStrength.getGsmSignalStrength();
r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
: gsmSignalStrength));
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
}
}
handleRemoveListLocked();
}
broadcastSignalStrengthChanged(signalStrength, linkId);
}
最后再看一下流程图: