Android10开机解锁问题剖析(一)

Android10开机解锁问题剖析(二)

Android10开机解锁问题剖析(三)

问题回忆

之前遇到一个开机解锁的问题,梳理了整个开机解锁的流程,并剖析了问题的根源,终究给出了两个计划:

  1. refreshSimData()不履行覆盖操作,以本地数据源为准,即直接返回false
  2. 持续深究为什么底层实在状况没有更改过来

计划1现已验证过,是收效的,现在持续剖析,为什么底层实在状况没有更改过来。

持续剖析

依据之前的剖析,Modem履行sim卡状况切换后会告诉上层,上层收到告诉会改写本地保持的sim卡状况,然后在改写时,是经过TelephonyManager自动获取Modem的状况来更新自己的状况的,具体代码在frameworks/base/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.javarefreshSimState()办法中

/**
     * @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数组初始化时,经过TelephonyComponentFactorymakePhone()办法创立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概述。

上述PhoneFactorymakeDefaultPhone()packages/services/Telephony/src/com/android/phone/PhoneGlobals.javaonCreate()中履行

/**
 * 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);
            //省掉部分代码
        }
        //省掉部分代码
    }
    //省掉部分代码
}

PhoneGloablsonCreate()办法在packages/services/Telephony/src/com/android/phone/PhoneApp.javaonCreate()办法中履行

/**
 * 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卡状况发生改变会给上层发送音讯,而此音讯会交由UiccControllerhandleMessage()来处理

@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.javagetIccCardStatus()办法的完结,在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的方式返回给上层,上层接收到音讯后持续在UiccControllerhandleMessage()办法中处理,即交由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里面的数据。

整体流程图

Android10开机解锁问题分析(三)

终究定论

TelephonyManager也是经过RIL自动去获取Modem端的数据,所以,Modem端是上层数据的唯一来历,故而猜想,Modem端在更新SIM卡状况的逻辑上仍是存在问题的。