Android10开机解锁问题剖析(二)
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卡状况的逻辑上仍是存在问题的。