您的位置:首页 > 其它

(M)SIM卡开机流程分析之显示名称加载

2017-04-27 17:50 435 查看
前面有说过,SIM卡的开机流程是从PhoneFactory.java文件中的makeDefaultPhone方法开始的,SIM的displayName也是从这部分开始的,接下来记录一下自己的研究成果

public static void makeDefaultPhone(Context context) {
synchronized (sLockProxyPhones) {
if (!sMadeDefaults) {
......
// Instantiate UiccController so that all other classes can just
// call getInstance()
// Leo,这个方法是开机后SIM卡启动过程中,较为重要的一个方法,需要注意
// Leo,获取UiccController的对象
mUiccController = UiccController.make(context, sCommandsInterfaces);

for (int i = 0; i < numPhones; i++) {
PhoneBase phone = null;
// Leo,根据Preferred Network Mode,获得SIM卡的PhoneType,从而确认Phone的类型,是GSMPhone还是CDMALTEPhone类型
int phoneType = TelephonyManager.getPhoneType(networkModes[i]);
if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
phone = new GSMPhone(context,
sCommandsInterfaces[i], sPhoneNotifier, i);
} else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
phone = new CDMALTEPhone(context,
sCommandsInterfaces[i], sPhoneNotifier, i);
}
Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " sub = " + i);

// Leo,Phone代理, 注意这个PhoneProxy是继承自Handler
sProxyPhones[i] = new PhoneProxy(phone);
}
......

Rlog.i(LOG_TAG, "Creating SubInfoRecordUpdater ");
sSubInfoRecordUpdater = new SubscriptionInfoUpdater(context,
sProxyPhones, sCommandsInterfaces);
......
}
}
}在此方法中,主要是做了如下几件事
1. 使用UiccController类的make方法,创建UiccController对象

2. 创建PhoneProxy代理类对象

3. new一个SubscriptionInfoUpdater对象

从此前的分析中,我们知道,UiccController类的make方法,主要是创建了UiccController对象,那么我们来具体看看代码

// Leo,单例模式,而且make方法只能够调用一次,否则抛出异常
public static UiccController make(Context c, CommandsInterface[] ci) {
synchronized (mLock) {
if (mInstance != null) {
throw new RuntimeException("MSimUiccController.make() should only be called once");
}
mInstance = new UiccController(c, ci);
return (UiccController)mInstance;
}
}
// Leo,第二个参数是RIL集合
private UiccController(Context c, CommandsInterface []ci) {
if (DBG) log("Creating UiccController");
mContext = c;
mCis = ci;
for (int i = 0; i < mCis.length; i++) {
Integer index = new Integer(i);
mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, index);
// TODO remove this once modem correctly notifies the unsols
if (DECRYPT_STATE.equals(SystemProperties.get("vold.decrypt"))) {
mCis[i].registerForAvailable(this, EVENT_ICC_STATUS_CHANGED, index);
} else {
mCis[i].registerForOn(this, EVENT_ICC_STATUS_CHANGED, index);
}
mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, index);
mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, index);
}
}
在UiccController的构造方法中,我们看到调用了RIL类的registerForIccStatusChanged方法,那么这个方法主要是做了什么操作呢?
@Override
public void registerForIccStatusChanged(Handler h, int what, Object obj) {
Registrant r = new Registrant (h, what, obj);
mIccStatusChangedRegistrants.add(r);
}通过传入的参数,创建Registrant对象,并且加入到mIccStatusChangedRegistrants中,而mIccStatusChangedRegistrants是RegistrantList对象。
接下来我们看下PhoneFactory的makeDefaultPhone方法中的第二个动作

sProxyPhones[i] = new PhoneProxy(phone);传入的参数,从前面的分析中,我们知道是GSMPhone对象(依旧以GSMPhone为例)
//***** Class Methods
// Leo,Phone代理,构造方法,这个PhoneBase对象就是在PhoneFactory中根据PreferredNetworkMode的出来的Phone对象
// 是CDMALTEPhone,或者GSMPhone
public PhoneProxy(PhoneBase phone) {
mActivePhone = phone;
......
// Leo,新建一个IccCardProxy对象
mIccCardProxy = new IccCardProxy(mContext, mCommandsInterface, mActivePhone.getPhoneId());

......
}我们看到,在PhoneProxy的构造方法中,新建了IccCardProxy对象,传入的参数为上下文对象,RIL对象,以及phoneId
public IccCardProxy(Context context, CommandsInterface ci, int phoneId) {
......
mContext = context;
mCi = ci;
mPhoneId = phoneId;
......
// Leo, 获取UiccController的对象,在PhoneFactory中已经调用过UiccController对象的make方法了,因此此处能够获取到其对象
mUiccController = UiccController.getInstance();
// Leo,调用UiccController对象方法,注册EVENT_ICC_CHANGED消息
mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
......
}在IccCardProxy的构造方法中,新建了UiccController对象,然后调用了其registerForIccChanged方法,注意其传入的参数,再进入UiccController的registerForIccChanged方法
//Notifies when card status changes
public void registerForIccChanged(Handler h, int what, Object obj) {
synchronized (mLock) {
Registrant r = new Registrant (h, what, obj);
mIccChangedRegistrants.add(r);
//Notify registrant right after registering, so that it will get the latest ICC status,
//otherwise which may not happen until there is an actual change in ICC status.
r.notifyRegistrant();
}
}这个方法中主要是做了两件事
1. 先新建了一个Registrant对象,将其加入mIccChangedRegistrants中

2. 调用了该对象的notifyRegistrant方法

第一条参照刚刚分析的,加入mIccChangedRegistrants

第二点,我们看看notifyRegistant方法

public void
notifyRegistrant()
{
internalNotifyRegistrant (null, null);
}
/*package*/ void
internalNotifyRegistrant (Object result, Throwable exception)
{
Handler h = getHandler();

if (h == null) {
clear();
} else {
Message msg = Message.obtain();

msg.what = what;

msg.obj = new AsyncResult(userObj, result, exception);

h.sendMessage(msg);
}
}
好,从这两个方法中,我们知道,其获取了Handler对象,并发送消息给自己,记得我们刚刚在IccCardProxy构造函数中传入的参数么?所以此处调用了IccCardProxy的handleMessage方法,且传入的消息的WHAT为EVENT_ICC_CHANGED,看IccCardProxy的handleMessage
public void handleMessage(Message msg) {
switch (msg.what) {
......
case EVENT_ICC_CHANGED:
if (mInitialized) {
updateIccAvailability();
}
break;
......
}
}
private void updateIccAvailability() {
    synchronized (mLock) {
        ......
        if (mIccRecords != newRecords || mUiccApplication != newApp || mUiccCard != newCard) {
            if (DBG) log("Icc changed. Reregestering.");
            unregisterUiccCardEvents();
            mUiccCard = newCard;
            mUiccApplication = newApp;
            mIccRecords = newRecords;
            registerUiccCardEvents();
        }
        updateExternalState();
    }
}
调用了registerUiccCardEvents方法
private void registerUiccCardEvents() {
if (mUiccCard != null) {
mUiccCard.registerForAbsent(this, EVENT_ICC_ABSENT, null);
}
if (mUiccApplication != null) {
mUiccApplication.registerForReady(this, EVENT_APP_READY, null);
mUiccApplication.registerForLocked(this, EVENT_ICC_LOCKED, null);
mUiccApplication.registerForNetworkLocked(this, EVENT_NETWORK_LOCKED, null);
}
if (mIccRecords != null) {
mIccRecords.registerForImsiReady(this, EVENT_IMSI_READY, null);
mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
}
}看到这个方法,结合前面的分析,我们知道,其主要做了
1. 调用UiccCard的registerForAbsent方法,主要是当SIM卡的状态为Absent时触发

2. 调用UiccApplication的三个Register方法,分别为当SIM卡状态为对应的状态时触发

3. 调用SIMRecords的三个register方法,分别在对应状态时调用

我们此处只分析SIMRecords的registerForRecordsLoaded方法,我们知道这个方法新建了一个Registrant对象,并存入mRecordsLoadedRegistrants中,当SIMRecords加载完毕后,发送EVENT_RECORDS_LOADED,从前面的分析中,我们也知道,只有mRecordsLoadedRegistrants的notifyRegistrants方法被调用时,才会调用Registrant的notifyRegistrant方法。

那么mRecordsLoadedRegistrants是什么时候,调用其notifyRegistrants的呢?

查看SIMRecords.java文件的onAllRecordsLoaded方法,从前面分析的SPN名称的时候,知道当SIMRecords加载结束后调用,而onAllRecordsLoaded方法的代码如下:

protected void onAllRecordsLoaded() {
......

mRecordsLoadedRegistrants.notifyRegistrants(
new AsyncResult(null, null, null));
}所以此时会调用IccCardProxy的handleMess
bafe
age,而且what为EVENT_RECORDS_LOADED
public void handleMessage(Message msg) {
switch (msg.what) {
......
case EVENT_RECORDS_LOADED:
// Update the MCC/MNC.
if (mIccRecords != null) {
String operator = mIccRecords.getOperatorNumeric();
log("operator=" + operator + " mPhoneId=" + mPhoneId);

if (operator != null) {
log("update icc_operator_numeric=" + operator);
mTelephonyManager.setSimOperatorNumericForPhone(mPhoneId, operator);
String countryCode = operator.substring(0,3);
if (countryCode != null) {
mTelephonyManager.setSimCountryIsoForPhone(mPhoneId,
MccTable.countryCodeForMcc(Integer.parseInt(countryCode)));
} else {
loge("EVENT_RECORDS_LOADED Country code is null");
}
} else {
loge("EVENT_RECORDS_LOADED Operator name is null");
}
}
if (mUiccCard != null && !mUiccCard.areCarrierPriviligeRulesLoaded()) {
mUiccCard.registerForCarrierPrivilegeRulesLoaded(
this, EVENT_CARRIER_PRIVILIGES_LOADED, null);
} else {
onRecordsLoaded();
}
break;
......
}
}在条件满足的时候,会调用其onRecordsLoaded方法
private void onRecordsLoaded() {
broadcastInternalIccStateChangedIntent(IccCardConstants.INTENT_VALUE_ICC_LOADED, null);
}
private void broadcastInternalIccStateChangedIntent(String value, String reason) {
synchronized (mLock) {
if (mPhoneId == null) {
loge("broadcastInternalIccStateChangedIntent: Card Index is not set; Return!!");
return;
}

Intent intent = new Intent(ACTION_INTERNAL_SIM_STATE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
| Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value);
intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
intent.putExtra(PhoneConstants.PHONE_KEY, mPhoneId);  // SubId may not be valid.
log("Sending intent ACTION_INTERNAL_SIM_STATE_CHANGED" + " for mPhoneId : " + mPhoneId);
ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
}
}
发送ACTION_INTERNAL_SIM_STATE_CHANGED广播
我们记得在PhoneFactory还有一条,SubscriptionInfoUpdater对象的新建,在其构造方法中注册了一个广播

public SubscriptionInfoUpdater(Context context, Phone[] phoneProxy, CommandsInterface[] ci) {
......
IntentFilter intentFilter = new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
intentFilter.addAction(IccCardProxy.ACTION_INTERNAL_SIM_STATE_CHANGED);
mContext.registerReceiver(sReceiver, intentFilter);
......
}因此SubscriptionInfoUpdater对象接收到广播后,处理
private final BroadcastReceiver sReceiver = new  BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
......
sendMessage(obtainMessage(EVENT_SIM_LOADED, slotId, -1));
......
}
};
public void handleMessage(Message msg) {
switch (msg.what) {
......
case EVENT_SIM_LOADED:
handleSimLoaded(msg.arg1);
break;
......
}
}
private void handleSimLoaded(int slotId) {
......

if (SubscriptionManager.isValidSubscriptionId(subId)) {
......
if (subInfo != null && subInfo.getNameSource() !=
SubscriptionManager.NAME_SOURCE_USER_INPUT) {
if (!TextUtils.isEmpty(simCarrierName)) {
nameToSet = simCarrierName;
} else {
nameToSet = "CARD " + Integer.toString(slotId + 1);
}
name.put(SubscriptionManager.DISPLAY_NAME, nameToSet);
logd("sim name = " + nameToSet);
contentResolver.update(SubscriptionManager.CONTENT_URI, name,
SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID
+ "=" + Long.toString(subId), null);
}

......
}
至此,SIM卡的displayName加载完成

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: