Android10开机解锁问题分析(三)
问题回顾
之前遇到一个开机解锁的问题,梳理了整个开机解锁的流程,并分析了问题的根源,最终给出了两个方案:
refreshSimData()
不执行覆盖操作,以本地数据源为准,即直接返回false- 继续深究为什么底层真实状态没有更改过来
方案1已经验证过,是生效的,现在继续分析,为什么底层真实状态没有更改过来。
继续分析
根据之前的分析,Modem执行sim卡状态切换后会通知上层,上层收到通知会刷新本地维持的sim卡状态,然后在刷新时,是通过TelephonyManager
主动获取Modem的状态来更新自己的状态的,具体代码在frameworks/base/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
的refreshSimState()
方法中
/**
* @return true if and only if the state has changed for the specified {@code slotId}
*/
private boolean refreshSimState(int subId, int slotId) {
// 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.intToState(simState);
} catch(IllegalArgumentException ex) {
Log.w(TAG, "Unknown sim state: " + simState);
state = State.UNKNOWN;
}
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 {
changed = (data.simState != state) || (data.slotId != slotId);
data.simState = state;
data.slotId = slotId;
}
return changed;
}
这里我们就要看看TelephonyManager
是如何获取SIM卡状态的,继续看tele.getSimState()
的源码
/**
* Returns a constant indicating the state of the device SIM card in a slot.
*
* @param slotIndex
*
* @see #SIM_STATE_UNKNOWN
* @see #SIM_STATE_ABSENT
* @see #SIM_STATE_PIN_REQUIRED
* @see #SIM_STATE_PUK_REQUIRED
* @see #SIM_STATE_NETWORK_LOCKED
* @see #SIM_STATE_READY
* @see #SIM_STATE_NOT_READY
* @see #SIM_STATE_PERM_DISABLED
* @see #SIM_STATE_CARD_IO_ERROR
* @see #SIM_STATE_CARD_RESTRICTED
*/
public int getSimState(int slotIndex) {
int simState = SubscriptionManager.getSimStateForSlotIndex(slotIndex);
if (simState == SIM_STATE_LOADED) {
simState = SIM_STATE_READY;
}
return simState;
}
/**
* Returns a constant indicating the state of sim for the slot index.
*
* @param slotIndex
*
* {@See TelephonyManager#SIM_STATE_UNKNOWN}
* {@See TelephonyManager#SIM_STATE_ABSENT}
* {@See TelephonyManager#SIM_STATE_PIN_REQUIRED}
* {@See TelephonyManager#SIM_STATE_PUK_REQUIRED}
* {@See TelephonyManager#SIM_STATE_NETWORK_LOCKED}
* {@See TelephonyManager#SIM_STATE_READY}
* {@See TelephonyManager#SIM_STATE_NOT_READY}
* {@See TelephonyManager#SIM_STATE_PERM_DISABLED}
* {@See TelephonyManager#SIM_STATE_CARD_IO_ERROR}
*
* {@hide}
*/
public static int getSimStateForSlotIndex(int slotIndex) {
int simState = TelephonyManager.SIM_STATE_UNKNOWN;
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
if (iSub != null) {
simState = iSub.getSimStateForSlotIndex(slotIndex);
}
} catch (RemoteException ex) {
}
return simState;
}
这里跨进程访问isub服务,isub服务的实现在frameworks/opt/telephony/src/java/com/android/internal/telephony/SubscriptionController.java
中
public class SubscriptionController extends ISub.Stub {
//省略部分代码
/**
* Get the SIM state for the slot index.
* For Remote-SIMs, this method returns {@link #IccCardConstants.State.UNKNOWN}
* @return SIM state as the ordinal of {@See IccCardConstants.State}
*/
@Override
public int getSimStateForSlotIndex(int slotIndex) {
State simState;
String err;
//判断slotIndex是否合法,默认是从0开始,小于0则为非法值
if (slotIndex < 0) {
simState = IccCardConstants.State.UNKNOWN;
err = "invalid slotIndex";
} else {
Phone phone = null;
try {
//根据slotIndex获取phone对象,这里获取的是GsmCdmaPhone对象
phone = PhoneFactory.getPhone(slotIndex);
} catch (IllegalStateException e) {
// ignore
}
if (phone == null) {
simState = IccCardConstants.State.UNKNOWN;
err = "phone == null";
} else {
//代码1:通过phone获取IccCard,里面保存着Sim卡的状态
IccCard icc = phone.getIccCard();
if (icc == null) {
simState = IccCardConstants.State.UNKNOWN;
err = "icc == null";
} else {
simState = icc.getState();
err = "";
}
}
}
if (VDBG) {
logd("getSimStateForSlotIndex: " + err + " simState=" + simState
+ " ordinal=" + simState.ordinal() + " slotIndex=" + slotIndex);
}
return simState.ordinal();
}
//省略部分代码
}
首先根据slotIndex获取Phone
对象,Phone
是一个抽象类,在PhoneFactory.getPhone()
方法中,是从sPhones
数组中获取phone对象
public class PhoneFactory {
//省略部分代码
static private Phone[] sPhones = null;
//省略部分代码
@UnsupportedAppUsage
public static void makeDefaultPhone(Context context) {
synchronized (sLockProxyPhones) {
if (!sMadeDefaults) {
//省略部分代码
//获取可用电话的数量,即Sim卡的数量
int numPhones = tm.getPhoneCount();
int[] networkModes = new int[numPhones];
//创建Phone数组
sPhones = new Phone[numPhones];
//创建RIL数组,RIL的作用是建立java和Modem通信
sCommandsInterfaces = new RIL[numPhones];
//省略部分代码
for (int i = 0; i < numPhones; i++) {
// reads the system properties and makes commandsinterface
// Get preferred network type.
networkModes[i] = RILConstants.PREFERRED_NETWORK_MODE;
Rlog.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkModes[i]));
//初始化RIL数组元素
sCommandsInterfaces[i] = telephonyComponentFactory.inject(RIL.class.getName()).
makeRIL(context, networkModes[i], cdmaSubscription, i);
}
//省略部分代码
//代码2:创建UiccController对象,这里传入了RIL数组,初始化该对象过程中会注册RIL监听,也就是建立与Modem之间的通信
sUiccController = UiccController.make(context, sCommandsInterfaces);
//省略部分代码
for (int i = 0; i < numPhones; i++) {
Phone phone = null;
int phoneType = TelephonyManager.getPhoneType(networkModes[i]);
TelephonyComponentFactory injectedComponentFactory =
telephonyComponentFactory.inject(GsmCdmaPhone.class.getName());
if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
//makePhone()方法返回的是GsmCdmaPhone对象
phone = injectedComponentFactory.makePhone(context,
sCommandsInterfaces[i], sPhoneNotifier, i,
PhoneConstants.PHONE_TYPE_GSM,
TelephonyComponentFactory.getInstance());
} else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
phone = injectedComponentFactory.makePhone(context,
sCommandsInterfaces[i], sPhoneNotifier, i,
PhoneConstants.PHONE_TYPE_CDMA_LTE,
TelephonyComponentFactory.getInstance());
}
Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " sub = " + i);
//初始化Phone数组元素
sPhones[i] = phone;
}
// Set the default phone in base class.
// FIXME: This is a first best guess at what the defaults will be. It
// FIXME: needs to be done in a more controlled manner in the future.
//设置默认值
if (numPhones > 0) {
sPhone = sPhones[0];
sCommandsInterface = sCommandsInterfaces[0];
}
//省略部分代码
}
}
}
@UnsupportedAppUsage
public static Phone getPhone(int phoneId) {
Phone phone;
String dbgInfo = "";
synchronized (sLockProxyPhones) {
if (!sMadeDefaults) {
throw new IllegalStateException("Default phones haven't been made yet!");
// CAF_MSIM FIXME need to introduce default phone id ?
} else if (phoneId == SubscriptionManager.DEFAULT_PHONE_INDEX) {
if (DBG) {
dbgInfo = "phoneId == DEFAULT_PHONE_ID return sPhone";
}
//取默认值
phone = sPhone;
} else {
if (DBG) {
dbgInfo = "phoneId != DEFAULT_PHONE_ID return sPhones[phoneId]";
}
//从sPhones数组中取值
phone = (phoneId >= 0 && phoneId < sPhones.length)
? sPhones[phoneId] : null;
}
if (DBG) {
Rlog.d(LOG_TAG, "getPhone:- " + dbgInfo + " phoneId=" + phoneId +
" phone=" + phone);
}
return phone;
}
}
//省略部分代码
}
sPhone
数组初始化时,通过TelephonyComponentFactory
的makePhone()
方法创建GsmCdmaPhone
对象,存入数组中
public class TelephonyComponentFactory {
//省略部分代码
public Phone makePhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
int phoneId, int precisePhoneType,
TelephonyComponentFactory telephonyComponentFactory) {
Rlog.i(TAG, "makePhone");
//创建GsmCdmaPhone对象
return new GsmCdmaPhone(context, ci, notifier, phoneId, precisePhoneType,
telephonyComponentFactory);
}
//省略部分代码
}
同时为每个Phone对象创建了RIL
对象,RIL
的作用就是建立java与Modem之间的通信,关于RIL的详细讲解可参考Android RIL概述。
上述PhoneFactory
的makeDefaultPhone()
在packages/services/Telephony/src/com/android/phone/PhoneGlobals.java
的onCreate()
中执行
/**
* Global state for the telephony subsystem when running in the primary
* phone process.
*/
public class PhoneGlobals extends ContextWrapper {
//省略部分代码
public void onCreate() {
//省略部分代码
if (mCM == null) {
//省略部分代码
// Initialize the telephony framework
PhoneFactory.makeDefaultPhones(this);
//省略部分代码
}
//省略部分代码
}
//省略部分代码
}
而PhoneGloabls
的onCreate()
方法在packages/services/Telephony/src/com/android/phone/PhoneApp.java
的onCreate()
方法中执行
/**
* Top-level Application class for the Phone app.
*/
public class PhoneApp extends Application {
PhoneGlobals mPhoneGlobals;
public PhoneApp() {
}
@Override
public void onCreate() {
if (UserHandle.myUserId() == 0) {
// We are running as the primary user, so should bring up the
// global phone state.
//创建PhoneGlobals对象
mPhoneGlobals = new PhoneGlobals(this);
//执行onCreate()方法
mPhoneGlobals.onCreate();
TelecomAccountRegistry.getInstance(this).setupOnBoot();
}
}
}
PhoneApp是电话app的启动入口,电话app在系统启动时就会自启动,也就是说,上述所有的初始化动作在系统启动后就会全部完成。也就意味着上面代码2处在系统启动后就会完成RIL监听注册,具体注册流程如下:
public class UiccController extends Handler {
public static UiccController make(Context c, CommandsInterface[] ci) {
synchronized (mLock) {
if (mInstance != null) {
throw new RuntimeException("UiccController.make() should only be called once");
}
mInstance = new UiccController(c, ci);
return mInstance;
}
}
private UiccController(Context c, CommandsInterface []ci) {
if (DBG) log("Creating UiccController");
mContext = c;
//RIL赋值
mCis = ci;
if (DBG) {
String logStr = "config_num_physical_slots = " + c.getResources().getInteger(
com.android.internal.R.integer.config_num_physical_slots);
log(logStr);
sLocalLog.log(logStr);
}
//省略部分代码
//获取Radio配置,用于RIL通信
mRadioConfig = RadioConfig.getInstance(mContext);
//注册Sim卡状态变化监听
mRadioConfig.registerForSimSlotStatusChanged(this, EVENT_SLOT_STATUS_CHANGED, null);
//注册Radio,建立RIL通信
for (int i = 0; i < mCis.length; i++) {
mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, i);
mCis[i].registerForAvailable(this, EVENT_RADIO_AVAILABLE, i);
mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, i);
mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, i);
}
//省略部分代码
}
}
注册监听之后,当Modem端的SIM卡状态发生变化会给上层发送消息,而此消息会交由UiccController
的handleMessage()
来处理
@Override
public void handleMessage (Message msg) {
synchronized (mLock) {
Integer phoneId = getCiIndex(msg);
if (phoneId < 0 || phoneId >= mCis.length) {
Rlog.e(LOG_TAG, "Invalid phoneId : " + phoneId + " received with event "
+ msg.what);
return;
}
sLocalLog.log("handleMessage: Received " + msg.what + " for phoneId " + phoneId);
AsyncResult ar = (AsyncResult)msg.obj;
switch (msg.what) {
//需要重点关注的消息
case EVENT_ICC_STATUS_CHANGED:
if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus");
mCis[phoneId].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE,
phoneId));
break;
case EVENT_RADIO_AVAILABLE:
case EVENT_RADIO_ON:
if (DBG) {
log("Received EVENT_RADIO_AVAILABLE/EVENT_RADIO_ON, calling "
+ "getIccCardStatus");
}
mCis[phoneId].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE,
phoneId));
// slot status should be the same on all RILs; request it only for phoneId 0
if (phoneId == 0) {
if (DBG) {
log("Received EVENT_RADIO_AVAILABLE/EVENT_RADIO_ON for phoneId 0, "
+ "calling getIccSlotsStatus");
}
mRadioConfig.getSimSlotsStatus(obtainMessage(EVENT_GET_SLOT_STATUS_DONE,
phoneId));
}
break;
//需要重点关注的消息
case EVENT_GET_ICC_STATUS_DONE:
if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");
onGetIccCardStatusDone(ar, phoneId);
break;
//需要重点关注的消息
case EVENT_SLOT_STATUS_CHANGED:
case EVENT_GET_SLOT_STATUS_DONE:
if (DBG) {
log("Received EVENT_SLOT_STATUS_CHANGED or EVENT_GET_SLOT_STATUS_DONE");
}
onGetSlotStatusDone(ar);
break;
case EVENT_RADIO_UNAVAILABLE:
if (DBG) log("EVENT_RADIO_UNAVAILABLE, dispose card");
UiccSlot uiccSlot = getUiccSlotForPhone(phoneId);
if (uiccSlot != null) {
uiccSlot.onRadioStateUnavailable();
}
mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, phoneId, null));
break;
case EVENT_SIM_REFRESH:
if (DBG) log("Received EVENT_SIM_REFRESH");
onSimRefresh(ar, phoneId);
break;
case EVENT_EID_READY:
if (DBG) log("Received EVENT_EID_READY");
onEidReady(ar, phoneId);
break;
default:
Rlog.e(LOG_TAG, " Unknown Event " + msg.what);
break;
}
}
}
在case EVENT_ICC_STATUS_CHANGED:
中,上层收到SIM状态更改的消息后,会通过RIL主动去获取底层的SIM卡状态,看frameworks/opt/telephony/src/java/com/android/internal/telephony/CommandsInterface.java
的getIccCardStatus()
方法的实现,在frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java
当中,RIL
实现了CommandsInterface
接口
import android.hardware.radio.V1_0.IRadio;
/**
* RIL implementation of the CommandsInterface.
*
* {@hide}
*/
public class RIL extends BaseCommands implements CommandsInterface {
//省略部分代码
@Override
public void getIccCardStatus(Message result) {
//以下为RIL的具体用法
//先得到一个IRadio接口,这是hal层的接口
IRadio radioProxy = getRadioProxy(result);
if (radioProxy != null) {
//创建一个RIL请求
RILRequest rr = obtainRequest(RIL_REQUEST_GET_SIM_STATUS, result,
mRILDefaultWorkSource);
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
try {
//发送请求,响应结果会以Message形式返回
radioProxy.getIccCardStatus(rr.mSerial);
} catch (RemoteException | RuntimeException e) {
handleRadioProxyExceptionForRR(rr, "getIccCardStatus", e);
}
}
}
//省略部分代码
}
RIL请求发送之后,Modem会将结果以Message的形式返回给上层,上层接收到消息后继续在UiccController
的handleMessage()
方法中处理,即交由onGetIccCardStatusDone()
方法处理
public class UiccController extends Handler {
public UiccSlot[] mUiccSlots;
//省略部分代码
private synchronized void onGetIccCardStatusDone(AsyncResult ar, Integer index) {
if (ar.exception != null) {
Rlog.e(LOG_TAG,"Error getting ICC status. "
+ "RIL_REQUEST_GET_ICC_STATUS should "
+ "never return an error", ar.exception);
return;
}
if (!isValidPhoneIndex(index)) {
Rlog.e(LOG_TAG,"onGetIccCardStatusDone: invalid index : " + index);
return;
}
//取出Modem返回的结果
IccCardStatus status = (IccCardStatus)ar.result;
sLocalLog.log("onGetIccCardStatusDone: phoneId " + index + " IccCardStatus: " + status);
int slotId = status.physicalSlotIndex;
if (VDBG) log("onGetIccCardStatusDone: phoneId " + index + " physicalSlotIndex " + slotId);
//非法值判断
if (slotId == INVALID_SLOT_ID) {
slotId = index;
}
if (eidIsNotSupported(status)) {
// we will never get EID from the HAL, so set mDefaultEuiccCardId to UNSUPPORTED_CARD_ID
if (DBG) log("eid is not supported");
mDefaultEuiccCardId = UNSUPPORTED_CARD_ID;
}
mPhoneIdToSlotId[index] = slotId;
if (VDBG) logPhoneIdToSlotIdMapping();
Log.d("jason", "onGetIccCardStatusDone, slotId="+slotId+", phoneId="+index+", IccCardStatus="+status);
if (mUiccSlots[slotId] == null) {
if (VDBG) {
log("Creating mUiccSlots[" + slotId + "]; mUiccSlots.length = "
+ mUiccSlots.length);
}
mUiccSlots[slotId] = new UiccSlot(mContext, true);
}
//更新本地数据,本地数据存放在mUiccSlots中,此数组在系统启动时完成初始化
mUiccSlots[slotId].update(mCis[index], status, index, slotId);
//省略部分代码
}
//省略部分代码
}
最终根据Modem返回的结果刷新本地数据
所以,代码1处,当获取到Phone对象之后,直接执行getIccCard()
获取Sim卡信息
public class GsmCdmaPhone extends Phone {
//省略部分代码
@Override
public IccCard getIccCard() {
// This function doesn't return null for backwards compatability purposes.
// To differentiate between cases where SIM is absent vs. unknown we return a dummy
// IccCard with the sim state set.
IccCard card = getUiccProfile();
if (card != null) {
return card;
} else {
UiccSlot slot = mUiccController.getUiccSlotForPhone(mPhoneId);
if (slot == null || slot.isStateUnknown()) {
return new IccCard(IccCardConstants.State.UNKNOWN);
} else {
return new IccCard(IccCardConstants.State.ABSENT);
}
}
}
private UiccProfile getUiccProfile() {
//执行UiccController的getUiccProfileForPhone()方法
return UiccController.getInstance().getUiccProfileForPhone(mPhoneId);
}
//省略部分代码
}
public class UiccController extends Handler {
public UiccSlot[] mUiccSlots;
//省略部分代码
/**
* API to get UiccSlot object for a given phone id
* @return UiccSlot object for the given phone id
*/
public UiccSlot getUiccSlotForPhone(int phoneId) {
synchronized (mLock) {
if (isValidPhoneIndex(phoneId)) {
int slotId = getSlotIdFromPhoneId(phoneId);
if (isValidSlotIndex(slotId)) {
//从mUiccSlots数组里获取
return mUiccSlots[slotId];
}
}
return null;
}
}
//省略部分代码
}
最终是从UiccController
对象中的mUiccSlots
数组中获取的,mUiccSlots
是在UiccController
创建时初始化,这个是系统启动之后执行的。并且根据上面分析的,在Modem
更新后,上层会同步更新mUiccSlots
里面的数据。
整体流程图
最终结论
TelephonyManager
也是通过RIL
主动去获取Modem端的数据,所以,Modem端是上层数据的唯一来源,故而猜测,Modem端在更新SIM卡状态的逻辑上还是存在问题的。
转载自:https://juejin.cn/post/7208465670992527421