问题回顾
之前剖析了Android10开机解锁流程(一),开始结论是底层SIM卡状况流经过错,后转给了Modem端来剖析,后面Modem端给出了剖析数据和结果,表明底层SIM卡状况流通正常,是上层状况流通异常。
持续剖析
所以,抱着挖出root cause的情绪,持续深入剖析了此问题。首要,依照Modem端的意思,底层跟上层应该都维护着一份SIM卡数据,底层数据更新后,经过广播和回调的方式通知上层更新自己的数据源。所以,我找到了上层SIM卡数据寄存的位置,坐落frameworks/base/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
,里面定义了一个HashMap
,用于寄存在SIM卡数据
public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
//省掉部分代码
//寄存sim卡数据
HashMap<Integer, SimData> mSimDatas = new HashMap<Integer, SimData>();
private static class SimData {
//sim卡状况
public State simState;
//sim卡槽id
public int slotId;
//sim卡id
public int subId;
SimData(State state, int slot, int id) {
simState = state;
slotId = slot;
subId = id;
}
//省掉部分代码
@Override
public String toString() {
return "SimData{state=" + simState + ",slotId=" + slotId + ",subId=" + subId + "}";
}
}
//省掉部分代码
}
其中map的键为subId(SIM卡id),值为SimData
目标,目标里定义了三个特点:simState
,slotId
,subId
在用户解锁SIM卡后,会顺次履行KeyguardSimPinView.verifyPasswordAndUnlock()
->KeyguardUpdateMonitor.reportSimUnlocked()
->handleSimStateChange()
,在handleSimStateChange()
办法里会更新Sim卡的状况,也便是SimData
的simState
值
public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
//省掉部分代码
HashMap<Integer, SimData> mSimDatas = new HashMap<Integer, SimData>();
/**
* Handle {@link #MSG_SIM_STATE_CHANGE}
*/
@VisibleForTesting
void handleSimStateChange(int subId, int slotId, State state) {
checkIsHandlerThread();
if (DEBUG_SIM_STATES) {
Log.d(TAG, "handleSimStateChange(subId=" + subId + ", slotId="
+ slotId + ", state=" + state +")");
}
boolean becameAbsent = false;
//判别subId是否有用
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
Log.w(TAG, "invalid subId in handleSimStateChange()");
/* Only handle No SIM(ABSENT) and Card Error(CARD_IO_ERROR) due to
* handleServiceStateChange() handle other case */
if (state == State.ABSENT) {
updateTelephonyCapable(true);
// Even though the subscription is not valid anymore, we need to notify that the
// SIM card was removed so we can update the UI.
becameAbsent = true;
mSimDatas.clear();
} else if (state == State.CARD_IO_ERROR) {
updateTelephonyCapable(true);
} else {
return;
}
}
//经过subId获取SimData
SimData data = mSimDatas.get(subId);
final boolean changed;
if (data == null) {
//获取不到,则创立
data = new SimData(state, slotId, subId);
mSimDatas.put(subId, data);
changed = true; // no data yet; force update
} else {
//更新SimData,changed表明是否有特点更新了
changed = (data.simState != state || data.subId != subId || data.slotId != slotId);
Log.d("jason", "update sim info: subId="+data.subId+", slotId="+data.slotId+", simState="+data.simState+"--->subId="+subId+", slotId="+slotId+", simState="+state);
data.simState = state;
data.subId = subId;
data.slotId = slotId;
}
//调试日志
Log.d("jason", " success update,print all sim data:");
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
mSimDatas.forEach(new BiConsumer<Integer, SimData>() {
@Override
public void accept(Integer integer, SimData simData) {
Log.d("jason", " " + simData.toString());
}
});
}
//回调
if ((changed || becameAbsent) && state != State.UNKNOWN) {
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onSimStateChanged(subId, slotId, state);
}
}
}
}
//省掉部分代码
}
当onSimStateChanged回调给上层之后,上层会触发Sim卡订阅信息更新的回调,也便是说,Sim卡状况改动了,Sim卡的订阅信息也随之发生改动,订阅监听器如下
public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
//省掉部分代码
private OnSubscriptionsChangedListener mSubscriptionListener =
new OnSubscriptionsChangedListener() {
@Override
public void onSubscriptionsChanged() {
//收到sim卡订阅信息更新后履行此处
mHandler.sendEmptyMessage(MSG_SIM_SUBSCRIPTION_INFO_CHANGED);
}
};
//省掉部分代码
}
当sim卡订阅信息发生改动时,经过mHandler
发送一个MSG_SIM_SUBSCRIPTION_INFO_CHANGED
音讯,mHandler
的handleMessage()
中经过handleSimSubscriptionInfoChanged()
处理此音讯
public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
//省掉部分代码
private void handleSimSubscriptionInfoChanged() {
if (DEBUG_SIM_STATES) {
Log.v(TAG, "onSubscriptionInfoChanged()");
List<SubscriptionInfo> sil = mSubscriptionManager.getActiveSubscriptionInfoList(false);
if (sil != null) {
for (SubscriptionInfo subInfo : sil) {
Log.v(TAG, "SubInfo:" + subInfo);
}
} else {
Log.v(TAG, "onSubscriptionInfoChanged: list is null");
}
}
//获取sim卡的订阅信息
List<SubscriptionInfo> subscriptionInfos = getSubscriptionInfo(true /* forceReload */);
// Hack level over 9000: Because the subscription id is not yet valid when we see the
// first update in handleSimStateChange, we need to force refresh all all SIM states
// so the subscription id for them is consistent.
ArrayList<SubscriptionInfo> changedSubscriptions = new ArrayList<>();
for (int i = 0; i < subscriptionInfos.size(); i++) {
SubscriptionInfo info = subscriptionInfos.get(i);
//刷新sim卡的状况,假如sim卡状况有改变,添加到改变列表中
boolean changed = refreshSimState(info.getSubscriptionId(), info.getSimSlotIndex());
if (changed) {
changedSubscriptions.add(info);
}
}
//调试日志
Log.d("jason", "changed subscription size is "+changedSubscriptions.size());
Log.d("jason", "print all sim subscription info:");
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
mSimDatas.forEach(new BiConsumer<Integer, SimData>() {
@Override
public void accept(Integer integer, SimData simData) {
Log.d("jason", " "+simData.toString());
}
});
}
//假如有sim卡状况发生改变,则再一次履行回调
for (int i = 0; i < changedSubscriptions.size(); i++) {
SimData data = mSimDatas.get(changedSubscriptions.get(i).getSubscriptionId());
for (int j = 0; j < mCallbacks.size(); j++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get();
if (cb != null) {
Log.d("jason", "onSimSubscriptionInfoChanged: subId:"+data.subId+", slotId:"+data.slotId+", simState:"+data.simState);
cb.onSimStateChanged(data.subId, data.slotId, data.simState);
}
}
}
//履行运行商信息更新回调
for (int j = 0; j < mCallbacks.size(); j++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get();
if (cb != null) {
cb.onRefreshCarrierInfo();
}
}
}
//省掉部分代码
}
先获取SIM卡的订阅信息,然后经过订阅信息判别是否有SIM卡状况发生改动,假如有则再次履行SIM卡状况更新回调,判别SIM卡状况发生改动的逻辑在refreshSimState()
办法中
public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
//省掉部分代码
/**
* @return true if and only if the state has changed for the specified {@code slotId}
*/
private boolean refreshSimState(int subId, int slotId) {
//代码1
// This is awful. It exists because there are two APIs for getting the SIM status
// that don't return the complete set of values and have different types. In Keyguard we
// need IccCardConstants, but TelephonyManager would only give us
// TelephonyManager.SIM_STATE*, so we retrieve it manually.
//经过TelephonyManager获取SIM卡状况
final TelephonyManager tele = TelephonyManager.from(mContext);
int simState = tele.getSimState(slotId);
State state;
try {
//将状况转化为State
state = State.intToState(simState);
} catch(IllegalArgumentException ex) {
Log.w(TAG, "Unknown sim state: " + simState);
state = State.UNKNOWN;
}
//在本地SIM卡数据源中获取对应的SimData目标
SimData data = mSimDatas.get(subId);
final boolean changed;
//更新本地SimData
if (data == null) {
data = new SimData(state, slotId, subId);
mSimDatas.put(subId, data);
changed = true; // no data yet; force update
} else {
changed = (data.simState != state) || (data.slotId != slotId);
Log.d("jason", "refresh sim state:"+data.simState+"-->"+state);
data.simState = state;
data.slotId = slotId;
}
return changed;
}
//省掉部分代码
}
OK,涉及到本地Sim卡数据源mSimDatas
的逻辑便是这些了,接下来经过本地日志检查数据源的改变进程,在捕获的logcat中发现一些问题
可以看到,在解锁完第二张SIM卡后,两张卡的状况均变为了READY
,但在刷新sim卡状况时,卡2的状况又从READY
变成了PIN_REQUIRED
,那为什么会变回去呢,我们来看一下refreshSimState()
办法中的解说,看上面代码1处的注释的解说
// This is awful. It exists because there are two APIs for getting the SIM status
// that don't return the complete set of values and have different types. In Keyguard we
// need IccCardConstants, but TelephonyManager would only give us
// TelephonyManager.SIM_STATE*, so we retrieve it manually.
大约意思是,这个办法存在,是因为有两个API去获取SIM的状况,这两个API回来不同类型的调集,并不是完好的调集,在Keyguard
中为IccCardConstants
,但是在TelephonyManager
中为TelephonyManager.SIM_STATE*
,有必要手动将TelephonyManager
类型检索成IccCardConstants
类型,这是一个糟糕的设计。
OK,现在我们明白了,refreshSimState()
办法的作用其实便是为了让本地数据源与实在数据坚持同步,也便是本地虽然符号为了READY
,但实际上SIM卡的状况并没有变为READY
,从长途获取到的SIM卡实在状况又从头掩盖了本地数据源的状况,这才导致状况从READY
又变回去了PIN_REQUIRED
解决方案
既然知道了上层问题原因地点,那么有两种方式来处理此问题
- refreshSimData()不履行掩盖操作,以本地数据源为准,即直接回来false
- 持续深究为什么底层实在状况没有更改过来
现在暂时选用方案1,然后小组内进行危险评价后再决议是否最终的处理方式,此问题后续持续跟进。