运营商显示流程分析之运营商信息的读取流程
一. SIM卡运营商信息的读取
从前面的 运营商信息的获取和赋值 可以知道SIM卡运营商的赋值最终是在 SIMRecords 中完成的, 而SIM卡信息的相关读取是在Uicc模块中
1.1. SIMRecords的创建流程
SIMRecords 的创建是在 UiccCardApplication 中完成的:
private IccRecords createIccRecords(AppType type, Context c, CommandsInterface ci) {
if (type == AppType.APPTYPE_USIM || type == AppType.APPTYPE_SIM) {
// 创建SIMRecords
return new SIMRecords(this, c, ci);
} else if (type == AppType.APPTYPE_RUIM || type == AppType.APPTYPE_CSIM){
return new RuimRecords(this, c, ci);
} else if (type == AppType.APPTYPE_ISIM) {
return new IsimUiccRecords(this, c, ci);
} else {
// Unknown app type (maybe detection is still in progress)
return null;
}
}
而 UiccCardApplication 的createIccRecords() 方法被调用是在 UiccCardApplication 的 构造方法 和 update() 方法中
UiccCardApplication(UiccCard uiccCard,
IccCardApplicationStatus as,
Context c,
CommandsInterface ci) {
...
mIccFh = createIccFileHandler(as.app_type);
// 创建SIMRecords
mIccRecords = createIccRecords(as.app_type, mContext, mCi);
...
}
void update (IccCardApplicationStatus as, Context c, CommandsInterface ci) {
synchronized (mLock) {
...
if (mAppType != oldAppType) {
if (mIccFh != null) { mIccFh.dispose();}
if (mIccRecords != null) { mIccRecords.dispose();}
mIccFh = createIccFileHandler(as.app_type);
// 创建SIMRecords
mIccRecords = createIccRecords(as.app_type, c, ci);
}
...
}
}
从上面可以看出 SIMRecords 在 UiccCardApplication 初始化的时候就已经被创建, 所以下面我们需要查看 UiccCardApplication 是在何处被创建的
1.2 UiccCardApplication的创建流程
通过搜索可以发现 UiccCardApplication 的 构造方法 和 update() 的调用都是在 UiccCard 的 update() 方法中
public void update(Context c, CommandsInterface ci, IccCardStatus ics) {
synchronized (mLock) {
...
CardState oldState = mCardState;
mCardState = ics.mCardState;
mUniversalPinState = ics.mUniversalPinState;
mGsmUmtsSubscriptionAppIndex = ics.mGsmUmtsSubscriptionAppIndex;
mCdmaSubscriptionAppIndex = ics.mCdmaSubscriptionAppIndex;
mImsSubscriptionAppIndex = ics.mImsSubscriptionAppIndex;
mContext = c;
mCi = ci;
//update applications
if (DBG) log(ics.mApplications.length + " applications");
for ( int i = 0; i < mUiccApplications.length; i++) {
if (mUiccApplications[i] == null) {
//Create newly added Applications
if (i < ics.mApplications.length) {
// UiccCardApplication的创建
mUiccApplications[i] = new UiccCardApplication(this,
ics.mApplications[i], mContext, mCi);
}
} else if (i >= ics.mApplications.length) {
//Delete removed applications
mUiccApplications[i].dispose();
mUiccApplications[i] = null;
} else {
//Update the rest
// UiccCardApplication的更新
mUiccApplications[i].update(ics.mApplications[i], mContext, mCi);
}
}
...
}
}
再看 UiccCard 的 update() 方法的调用是在 UiccCard 的 构造方法 和 UiccController 的 onGetIccCardStatusDone() 方法中, 而 UiccCard 的构造方法最终也在 UiccController 的 onGetIccCardStatusDone() 中被调用, 所以接下来直接查看 UiccController
1.3. UiccController的创建流程
先查看 UiccController 的 onGetIccCardStatusDone() 方法:
private synchronized void onGetIccCardStatusDone(AsyncResult ar) {
...
IccCardStatus status = (IccCardStatus)ar.result;
// 创建和更新UiccCard
if (mUiccCard == null) {
//Create new card
mUiccCard = new UiccCard(mContext, mCi, status);
} else {
//Update already existing card
mUiccCard.update(mContext, mCi , status);
}
if (DBG) log("Notifying IccChangedRegistrants");
mIccChangedRegistrants.notifyRegistrants();
}
而 onGetIccCardStatusDone() 的调用是在 handleMessage() 方法中
@Override
public void handleMessage (Message msg) {
synchronized (mLock) {
switch (msg.what) {
case EVENT_ICC_STATUS_CHANGED:
...
// 首先获取到IccCard状态改变的消息, 然后主动查询, 然后在下面的 EVENT_GET_ICC_STATUS_DONE 逻辑中获取处理IccCard的状态信息
mCi.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
break;
case EVENT_GET_ICC_STATUS_DONE:
...
// 接收处理IccCard的窗台信息
AsyncResult ar = (AsyncResult)msg.obj;
onGetIccCardStatusDone(ar);
break;
...
default:
Rlog.e(LOG_TAG, " Unknown Event " + msg.what);
}
}
}
至此, 我们需要知道 EVENT_ICC_STATUS_CHANGED 消息是谁发送的? 在Android的源码中, 很多的使用观察者模式, 通过将 Message 和Handler 进行注册其他的类中, 当前其他类的状态发生改变, 通过注册的 Handler 和 Message 回调到进行注册的类, 此处我们需要查看该消息是在何处被注册的, 在 UiccController的构造方法中
public UiccController(Context c, CommandsInterface ci) {
mContext = c;
mCi = ci; // ci 即 RIL
// 注册EVENT_ICC_STATUS_CHANGED消息
mCi.registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, null);
mCi.registerForOn(this, EVENT_ICC_STATUS_CHANGED, null);
mCi.registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, null);
}
1.4. UiccController的创建流程
UiccController 的创建是在 PhoneFactory 中
/**
* FIXME replace this with some other way of making these
* instances
*/
public static void makeDefaultPhone(Context context) {
synchronized(Phone.class) {
if (!sMadeDefaults) {
...
//reads the system properties and makes commandsinterface
sCommandsInterface = new RIL(context, networkMode, cdmaSubscription);
// Instantiate UiccController so that all other classes can just call getInstance()
// 创建UiccController
UiccController.make(context, sCommandsInterface);
int phoneType = TelephonyManager.getPhoneType(networkMode);
if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
Rlog.i(LOG_TAG, "Creating GSMPhone");
// 创建GSMPhone
sProxyPhone = new PhoneProxy(new GSMPhone(context,
sCommandsInterface, sPhoneNotifier));
}
...
}
}
}
而 UiccController 的 makeDefaultPhone() 的调用是在 PhoneGlobals 的 onCreate() 方法中
1.5 PhoneGlobals的onCreate()方法
public void onCreate() {
...
if (phone == null) {
// Initialize the telephony framework
PhoneFactory.makeDefaultPhones(this);
// Get the default phone
phone = PhoneFactory.getDefaultPhone();
// Start TelephonyDebugService After the default phone is created.
Intent intent = new Intent(this, TelephonyDebugService.class);
startService(intent);
mCM = CallManager.getInstance();
mCM.registerPhone(phone);
...
}
}
PhoneGlobals 的 onCreate() 被调用是在 PhoneApp 的 onCreate() 方法中
1.6. PhoneApp 的 onCreate() 方法
public class PhoneApp extends Application {
public void onCreate() {
if (UserHandle.myUserId() == 0) {
mPhoneGlobals = new PhoneGlobals(this);
mPhoneGlobals.onCreate();
}
}
}
至此, SIMRecords 的创建流程已经完成, PhoneApp 的加载是系统 com.android.phone 进程时加载
因为SIM卡的运营商信息是通过 SIMRecords 获取的, 因此我们需要了解 SIMRecords 的创建流程, 接下看SIM卡信息的读取流程
二. SIM卡运营商信息的读取流程
接着上面 SIMRecords 的创建, 我们首先看 SIMRecords 的构造方法:
public SIMRecords(UiccCardApplication app, Context c, CommandsInterface ci) {
super(app, c, ci);
...
// Start off by setting empty state
resetRecords();// 重置SIM卡的相关状态信息
// 注册EVENT_APP_READY的Message消息, 该消息被注册到UiccCardApplication中,
// 当UiccApplication的update()方法被调用时, 执行回调发送该消息
// 而UiccApplication的update()方法的调用已经在上面说明
mParentApp.registerForReady(this, EVENT_APP_READY, null);
if (DBG) log("SIMRecords X ctor this=" + this);
}
查看 EVENT_APP_READY 消息的处理:
public void handleMessage(Message msg) {
...
try { switch (msg.what) {
case EVENT_APP_READY:
onReady();//
break;
...
}
}
protected void fetchSimRecords() {
mRecordsRequested = true;
...
// 我们只关心SPN的获取, 所以看此处
getSpnFsm(true, null);
...
}
获取 SPN 的流程:
/**
* Finite State Machine to load Service Provider Name , which can be stored
* in either EF_SPN (3GPP), EF_SPN_CPHS, or EF_SPN_SHORT_CPHS (CPHS4.2)
*
* After starting, FSM will search SPN EFs in order and stop after finding
* the first valid SPN
*
* If the FSM gets restart while waiting for one of
* SPN EFs results (i.e. a SIM refresh occurs after issuing
* read EF_CPHS_SPN), it will re-initialize only after
* receiving and discarding the unfinished SPN EF result.
*
* @param start set true only for initialize loading
* @param ar the AsyncResult from loadEFTransparent
* ar.exception holds exception in error
* ar.result is byte[] for data in success
*/
private void getSpnFsm(boolean start, AsyncResult ar) {
byte[] data;
// start: 第一次执行为 true, 后续执行为false
if (start) {
// 初始化获取SPN的状态
// Check previous state to see if there is outstanding
// SPN read
if(mSpnState == GetSpnFsmState.READ_SPN_3GPP ||
mSpnState == GetSpnFsmState.READ_SPN_CPHS ||
mSpnState == GetSpnFsmState.READ_SPN_SHORT_CPHS ||
mSpnState == GetSpnFsmState.INIT) {
// Set INIT then return so the INIT code
// will run when the outstanding read done.
mSpnState = GetSpnFsmState.INIT;
return;
} else {
// 开始为INIT状态
mSpnState = GetSpnFsmState.INIT;
}
}
// 执行顺序INIT --> READ_SPN_3GPP --> READ_SPN_CPHS --> READ_SPN_SHORT_CPHS, 执行顺序由3GPP协议确定
switch(mSpnState){
case INIT:
mSpn = null;
// 加载EF_SPN, 回调到 EVENT_GET_SPN_DONE 消息处理
mFh.loadEFTransparent(EF_SPN,
obtainMessage(EVENT_GET_SPN_DONE));
mRecordsToLoad++;
// 修改状态
mSpnState = GetSpnFsmState.READ_SPN_3GPP;
break;
case READ_SPN_3GPP:
if (ar != null && ar.exception == null) {
// EF_SPN 加载成功
data = (byte[]) ar.result;
mSpnDisplayCondition = 0xff & data[0];
mSpn = IccUtils.adnStringFieldToString(data, 1, data.length - 1);
if (DBG) log("Load EF_SPN: " + mSpn
+ " spnDisplayCondition: " + mSpnDisplayCondition);
// 获取到的运营商名称, 即通过TelephonyManager.getSimOperatorName()方法获取
SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, mSpn);
mSpnState = GetSpnFsmState.IDLE;
} else {
// EF_SPN 加载失败, 加载 EF_SPN_CPHS, 回调到 EVENT_GET_SPN_DONE 消息处理
mFh.loadEFTransparent( EF_SPN_CPHS,
obtainMessage(EVENT_GET_SPN_DONE));
mRecordsToLoad++;
mSpnState = GetSpnFsmState.READ_SPN_CPHS;
// See TS 51.011 10.3.11. Basically, default to
// show PLMN always, and SPN also if roaming.
mSpnDisplayCondition = -1;
}
break;
case READ_SPN_CPHS:
if (ar != null && ar.exception == null) {
// 加载 EF_SPN_CPHS 成功
data = (byte[]) ar.result;
mSpn = IccUtils.adnStringFieldToString(data, 0, data.length);
if (DBG) log("Load EF_SPN_CPHS: " + mSpn);
// 获取到的运营商名称, 即通过TelephonyManager.getSimOperatorName()方法获取
SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, mSpn);
mSpnState = GetSpnFsmState.IDLE;
} else {
// 加载 EF_SPN_CPHS 失败, 加载 EF_SPN_SHORT_CPHS, 回调到 EVENT_GET_SPN_DONE 消息处理
mFh.loadEFTransparent(
EF_SPN_SHORT_CPHS, obtainMessage(EVENT_GET_SPN_DONE));
mRecordsToLoad++;
mSpnState = GetSpnFsmState.READ_SPN_SHORT_CPHS;
}
break;
case READ_SPN_SHORT_CPHS:
if (ar != null && ar.exception == null) {
// 加载 EF_SPN_SHORT_CPHS 成功
data = (byte[]) ar.result;
mSpn = IccUtils.adnStringFieldToString(data, 0, data.length);
if (DBG) log("Load EF_SPN_SHORT_CPHS: " + mSpn);
// 获取到的运营商名称, 即通过TelephonyManager.getSimOperatorName()方法获取
SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, mSpn);
}else {
if (DBG) log("No SPN loaded in either CHPS or 3GPP");
}
mSpnState = GetSpnFsmState.IDLE;
break;
default:
mSpnState = GetSpnFsmState.IDLE;
}
}
接着查看 EVENT_GET_SPN_DONE 消息的处理:
@Override
public void handleMessage(Message msg) {
try { switch (msg.what) {
case EVENT_GET_SPN_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
// 注意: 第一参数为 false
getSpnFsm(false, ar);// 继续执行getSpnFsm()方法
break;
} finally {
// Count up record load responses even if they are fails
if (isRecordLoadResponse) {
// 当获取到SPN后执行该方法
onRecordLoaded();
}
}
}
protected void onRecordLoaded() {
// One record loaded successfully or failed, In either case
// we need to update the recordsToLoad count
mRecordsToLoad -= 1;
if (DBG) log("onRecordLoaded " + mRecordsToLoad + " requested: " + mRecordsRequested);
if (mRecordsToLoad == 0 && mRecordsRequested == true) {
// 所有信息都已加载完成
onAllRecordsLoaded();
} else if (mRecordsToLoad < 0) {
loge("recordsToLoad <0, programmer error suspected");
mRecordsToLoad = 0;
}
}
查看对已经获取到的 SIM卡信息 的处理:
@Override
protected void onAllRecordsLoaded() {
if (DBG) log("record load complete");
// Some fields require more than one SIM record to set
// 获取到运营商代码
String operator = getOperatorNumeric();
if (!TextUtils.isEmpty(operator)) {
log("onAllRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" +
operator + "'");
// 保存运营商代码, 即通过TelephonyManager.getSimOperator()方法获取
SystemProperties.set(PROPERTY_ICC_OPERATOR_NUMERIC, operator);
} else {
log("onAllRecordsLoaded empty 'gsm.sim.operator.numeric' skipping");
}
if (!TextUtils.isEmpty(mImsi)) {
log("onAllRecordsLoaded set mcc imsi=" + mImsi);
SystemProperties.set(PROPERTY_ICC_OPERATOR_ISO_COUNTRY,
MccTable.countryCodeForMcc(Integer.parseInt(mImsi.substring(0,3))));
} else {
log("onAllRecordsLoaded empty imsi skipping setting mcc");
}
setVoiceMailByCountry(operator);
setSpnFromConfig(operator);
mRecordsLoadedRegistrants.notifyRegistrants(
new AsyncResult(null, null, null));
}
private void setSpnFromConfig(String carrier) {
// 如果本地有配置运营商名称, 则覆盖从SIM卡中获取到的SIM卡运营商名称
// 本地配置的文件是: spn-conf.xml文件
if (mSpnOverride.containsCarrier(carrier)) {
mSpn = mSpnOverride.getSpn(carrier);
}
}