前言
Android N
Log分析
04-13 16:47:03.475 D/RILJ ( 2168): [8442]> DATA_REGISTRATION_STATE [SUB0]
04-13 16:47:03.651 D/RILJ ( 2168): [8442]< DATA_REGISTRATION_STATE {1, null, 02f0b403, 14, null, 20, 10410, null, null, null, null} [SUB0]
一般我们会看到这样注册的Log,但是这个注册的流程是怎样的呢?我们先来看注册流程。
注册流程
前面UICC模块的我们就跳过了,想了解的小伙伴儿自己查资料了解一下,直接到ICC Change开始。
在ServiceStateTracker.java中:
1、注册EVENT_ICC_CHANGED
public ServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci) {
mPhone = phone;
mCi = ci;
mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
}
2、监听EVENT_ICC_CHANGED
public void handleMessage(Message msg) {
AsyncResult ar;
int[] ints;
Message message;
switch (msg.what) {
case EVENT_ICC_CHANGED:
onUpdateIccAvailability();
break;
}
}
3、调用onUpdateIccAvailability()
protected void onUpdateIccAvailability() {
if (mPhone.isPhoneTypeGsm()) {
mUiccApplcation.registerForReady(this, EVENT_SIM_READY, null);
if (mIccRecords != null) {
mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
}
}
}
4、监听EVENT_SIM_READY
case EVENT_SIM_READY:
// Reset the mPreviousSubId so we treat a SIM power bounce
// as a first boot. See b/19194287
mOnSubscriptionsChangedListener.mPreviousSubId.set(-1);
pollState();
// Signal strength polling stops when radio is off
queueNextSignalStrengthPoll();
break;
5、调用pollState()
/**
* A complete "service state" from our perspective is
* composed of a handful of separate requests to the radio.
*
* We make all of these requests at once, but then abandon them
* and start over again if the radio notifies us that some
* event has changed
*/
public void pollState() {
pollState(false);
}
/**
* We insist on polling even if the radio says its off.
* Used when we get a network changed notification
* but the radio is off - part of iwlan hack
*/
private void modemTriggeredPollState() {
pollState(true);
}
这里需要注意一下,这里有两个调用pollState(boolean XXX)
的地方,看函数名也知道:
1)第一个函数是在插拔卡的时候会调用;
2)第二个函数是在网络变化的时候时候调用的。
如下:
mCi.registerForVoiceNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED, null);
case EVENT_NETWORK_STATE_CHANGED:
modemTriggeredPollState();
break;
6、接着继续调用有参数的pollState(boolean modemTriggered)
public void pollState(boolean modemTriggered) {
mPollingContext = new int[1];
mPollingContext[0] = 0;
switch (mCi.getRadioState()) {
case RADIO_UNAVAILABLE:
... ...
case RADIO_OFF:
... ...
default:
if (modemTriggered) mIsModemTriggeredPollingPending = true;
// Issue all poll-related commands at once then count down the responses, which
// are allowed to arrive out-of-order
mPollingContext[0]++;
mCi.getOperator(obtainMessage(EVENT_POLL_STATE_OPERATOR, mPollingContext));
mPollingContext[0]++;
//获取数据注册状态
mCi.getDataRegistrationState(obtainMessage(EVENT_POLL_STATE_GPRS, mPollingContext));
mPollingContext[0]++;
//获取语音注册状态
mCi.getVoiceRegistrationState(obtainMessage(EVENT_POLL_STATE_REGISTRATION,
mPollingContext));
if (mPhone.isPhoneTypeGsm()) {
mPollingContext[0]++;
mCi.getNetworkSelectionMode(obtainMessage(
EVENT_POLL_STATE_NETWORK_SELECTION_MODE, mPollingContext));
}
break;
}
}
7、监听EVENT_POLL_STATE_GPRS等
case EVENT_POLL_STATE_REGISTRATION:
case EVENT_POLL_STATE_GPRS:
case EVENT_POLL_STATE_OPERATOR:
ar = (AsyncResult) msg.obj;
handlePollStateResult(msg.what, ar);
break;
8、调用handlePollStateResult()
protected void handlePollStateResult(int what, AsyncResult ar) {
... ...
pollStateDone();
}
9、轮询状态完成pollStateDone()
private void pollStateDone() {
mIsModemTriggeredPollingPending = false;
if (mPhone.isPhoneTypeGsm()) {
pollStateDoneGsm();
} else if (mPhone.isPhoneTypeCdma()) {
pollStateDoneCdma();
} else {
pollStateDoneCdmaLte();
}
}
10、分网络类型调用,如pollStateDoneGsm()
protected GsmCdmaPhone mPhone;
private void pollStateDoneGsm() {
mPhone.notifyServiceStateChanged(mSS);
}
11、通知GsmCdmaPhone等变化
在GsmCdmaPhone.java中:
public class GsmCdmaPhone extends Phone {
... ...
public void notifyServiceStateChanged(ServiceState ss) {
super.notifyServiceStateChangedP(ss);
}
... ...
}
Phone.java
protected PhoneNotifier mNotifier;
protected void notifyServiceStateChangedP(ServiceState ss) {
AsyncResult ar = new AsyncResult(null, ss, null);
mServiceStateRegistrants.notifyRegistrants(ar);
mNotifier.notifyServiceState(this);
}
DefaultPhoneNotifier.java
public class DefaultPhoneNotifier implements PhoneNotifier {
protected ITelephonyRegistry mRegistry;
@Override
public void notifyServiceState(Phone sender) {
ServiceState ss = sender.getServiceState();
int phoneId = sender.getPhoneId();
int subId = sender.getSubId();
Rlog.d(LOG_TAG, "nofityServiceState: mRegistry=" + mRegistry + " ss=" + ss
+ " sender=" + sender + " phondId=" + phoneId + " subId=" + subId);
if (ss == null) {
ss = new ServiceState();
ss.setStateOutOfService();
}
try {
if (mRegistry != null) {
//在这里继续调用
mRegistry.notifyServiceStateForPhoneId(phoneId, subId, ss);
}
} catch (RemoteException ex) {
// system process is dead
}
}
}
TelephonyRegistry.java
class TelephonyRegistry extends ITelephonyRegistry.Stub {
... ...
public void notifyServiceStateForPhoneId(int phoneId, int subId, ServiceState state) {
if (!checkNotifyPermission("notifyServiceState()")){
return;
}
synchronized (mRecords) {
if (VDBG) {
log("notifyServiceStateForSubscriber: subId=" + subId + " phoneId=" + phoneId
+ " state=" + state);
}
if (validatePhoneId(phoneId)) {
mServiceState[phoneId] = state;
logServiceStateChanged("notifyServiceStateForSubscriber", subId, phoneId, state);
if (VDBG) toStringLogSSC("notifyServiceStateForSubscriber");
for (Record r : mRecords) {
if (VDBG) {
log("notifyServiceStateForSubscriber: r=" + r + " subId=" + subId
+ " phoneId=" + phoneId + " state=" + state);
}
if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SERVICE_STATE) &&
idMatch(r.subId, subId, phoneId)) {
try {
if (DBG) {
log("notifyServiceStateForSubscriber: callback.onSSC r=" + r
+ " subId=" + subId + " phoneId=" + phoneId
+ " state=" + state);
}
//在这里回调
r.callback.onServiceStateChanged(new ServiceState(state));
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
}
}
} else {
log("notifyServiceStateForSubscriber: INVALID phoneId=" + phoneId);
}
handleRemoveListLocked();
}
//发出广播,通知Service state改变了
broadcastServiceStateChanged(state, phoneId, subId);
}
}
12、最后在PhoneStateListener()中回调
private static class IPhoneStateListenerStub extends IPhoneStateListener.Stub {
private WeakReference<PhoneStateListener> mPhoneStateListenerWeakRef;
public IPhoneStateListenerStub(PhoneStateListener phoneStateListener) {
mPhoneStateListenerWeakRef = new WeakReference<PhoneStateListener>(phoneStateListener);
}
private void send(int what, int arg1, int arg2, Object obj) {
PhoneStateListener listener = mPhoneStateListenerWeakRef.get();
if (listener != null) {
Message.obtain(listener.mHandler, what, arg1, arg2, obj).sendToTarget();
}
}
public void onServiceStateChanged(ServiceState serviceState) {
send(LISTEN_SERVICE_STATE, 0, 0, serviceState);
}
... ...
}
监听:
public PhoneStateListener(int subId, Looper looper) {
mSubId = subId;
mHandler = new Handler(looper) {
public void handleMessage(Message msg) {
switch (msg.what) {
case LISTEN_SERVICE_STATE:
PhoneStateListener.this.onServiceStateChanged((ServiceState)msg.obj);
break;
... ...
}
... ...
13、轮询过程中存在的问题
在做某些测试的时候,会出现不显示4G图标,并且不能上网的情况。
情况简述:
开关飞行模式,状态栏不显示4G图标且不能上网。
简要分析:
这个跟系统时序有关,pollstate更新事件会导致mPollingContext
值被覆盖,从而可能导致之前的data注册状态信息无法更新到Telephony中。
如果开关飞行模式时间延长一点,应该就不会有问题。
//开关飞行模式
04-23 10:39:33.078 D/RILJ ( 2149): [3581]> RADIO_POWER off [SUB0]
04-23 10:39:33.185 D/RILJ ( 2149): [3586]> RADIO_POWER off [SUB1]
04-23 10:39:34.781 D/RILJ ( 2149): [3581]< RADIO_POWER [SUB0]
04-23 10:39:34.824 D/RILJ ( 2149): [3586]< RADIO_POWER [SUB1]
04-23 10:39:35.737 D/RILJ ( 2149): [3610]> RADIO_POWER on [SUB0]
04-23 10:39:35.742 D/RILJ ( 2149): [3611]> RADIO_POWER on [SUB1]
04-23 10:39:35.834 D/RILJ ( 2149): [3610]< RADIO_POWER [SUB0]
04-23 10:39:35.854 D/RILJ ( 2149): [3611]< RADIO_POWER [SUB1]
04-23 10:39:36.027 D/SST ( 2149): EVENT_RADIO_POWER_OFF_DONE
04-23 10:39:36.493 D/SST ( 2149): EVENT_RADIO_POWER_OFF_DONE
//打开飞行模式前的一次状态上报
04-23 10:39:33.168 D/RILJ ( 2149): [3583]< DATA_REGISTRATION_STATE {1, null, 02f0b403, 14, null, 20, 10410, 61, 49329155, null, null} [SUB0]
//飞行模式之后的驻上网时间
04-23 10:39:35.940 D/RILJ ( 2149): [3619]< DATA_REGISTRATION_STATE {2, null, null, null, 0, 20, null, null, null, null, null} [SUB0]
//... ...(省略11次)
04-23 10:39:38.775 D/RILJ ( 2149): [3710]< DATA_REGISTRATION_STATE {1, null, 02f0b403, 14, null, 20, 10410, 61, 49329155, null, null} [SUB0]
虽然卡1上报了13次data状态变化消息(包含从无服务到有服务的过程),但最终只有最后一次的状态变化真正更新到telephony中,而这个状态刚好跟打开飞行模式之前的状态一致。
1)一旦进入pollstate函数中,就会重新构造mPollingContext
:
public void pollState(boolean modemTriggered) {
mPollingContext = new int[1];
mPollingContext[0] = 0;
... ...
}
2)检查mPollingContext
是否与当前一致:
在处理DATA_REGISTRATION_STATE事件时,会先检查发起request的mPollingContext
跟当前的mPollingContext
是否一致,如果不一致,直接跳过了;
所以导致data注册状态变化消息无法更新的原因就是:mPollingContext
覆盖
protected void handlePollStateResult(int what, AsyncResult ar) {
// Ignore stale requests from last poll
if (ar.userObj != mPollingContext) return;
... ...
}
3)系统时序的时间差分析
//打开飞行模式后,底层上报radio off,然后会发通知;
04-23 10:39:34.811 D/RILJ ( 2149): [UNSL]< UNSOL_RESPONSE_RADIO_STATE_CHANGED RADIO_OFF [SUB0]
//收到通知处理状态改变事件时,可以看到这时获取的radio state是RADIO_ON;
04-23 10:39:35.917 D/SST ( 2149): pollState: radio state =RADIO_ON mDeviceShuttingDown = false
(此处的Log需要自己在pollState()中自行添加。)
//这是因为在10:39:35.917时间点之前已经关闭飞行模式,底层已经上报RADIO_ON的状态了。
04-23 10:39:35.908 D/RILJ ( 2149): [UNSL]< UNSOL_RESPONSE_RADIO_STATE_CHANGED RADIO_ON [SUB0]
这种为时序性、概率性问题,比较难优化,所以建议在开关飞行模式时间延长几秒钟。
分析到这里就结束了,分析得比较粗浅,哪里分析不对的,希望各路大神可以指出来,谢谢~