(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;
}
}
@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);
}
public void handleMessage(Message msg) {
switch (msg.what) {
......
case EVENT_ICC_CHANGED:
if (mInitialized) {
updateIccAvailability();
}
break;
......
}
}
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);
}
我们记得在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对象接收到广播后,处理
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加载完成
相关文章推荐
- Android 4.4Telephony流程分析SIM卡开机时的数据加载
- Android4.4 Telephony流程分析——SIM卡开机时的数据加载
- Android 4.4Telephony流程分析SIM卡开机时的初始化
- 从代码分析Android-Universal-Image-Loader的图片加载、显示流程
- android 6.0 SystemUI源码分析(3)-Recent Panel加载显示流程
- (M)SIM卡开机流程分析之默认APN设置
- 从代码分析Android-Universal-Image-Loader的图片加载、显示流程
- Android4.4 Telephony流程分析——SIM卡开机时的初始化
- (M)SIM卡开机流程分析之RIL类分析
- (M)SIM卡开机流程分析之TelephonyDevController类分析
- Android 开源框架Universal-Image-Loader完全解析(五)- 从代码分析Android-Universal-Image-Loader的图片加载、显示流程
- 从代码分析Android-Universal-Image-Loader的图片加载、显示流程
- Launcher3 开机后应用数据的加载流程分析
- (M)SIM卡开机流程分析之DefaultPhoneNotifier类分析
- 从代码分析Android-Universal-Image-Loader的图片加载、显示流程
- [Android5.1]开机动画显示工作流程分析
- Android 7.0 Gallery图库源码分析3 - 数据加载及显示流程
- (M)SIM卡开机流程分析之SubscriptionController类分析
- (M)SIM卡开机流程分析之UiccController类分析
- (M)SIM卡开机流程分析之主线分析