Android系统分析之运营商显示流程分析之运营商信息的读取流程二

运营商显示流程分析之运营商信息的读取流程

一. 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;
    }
}

UiccCardApplicationcreateIccRecords() 方法被调用是在 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);
        }
        ...
    }
}

从上面可以看出 SIMRecordsUiccCardApplication 初始化的时候就已经被创建, 所以下面我们需要查看 UiccCardApplication 是在何处被创建的

1.2 UiccCardApplication的创建流程

通过搜索可以发现 UiccCardApplication构造方法update() 的调用都是在 UiccCardupdate() 方法中

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);
            }
        }
        ...
    }
}

再看 UiccCardupdate() 方法的调用是在 UiccCard构造方法UiccControlleronGetIccCardStatusDone() 方法中, 而 UiccCard 的构造方法最终也在 UiccControlleronGetIccCardStatusDone() 中被调用, 所以接下来直接查看 UiccController

1.3. UiccController的创建流程

先查看 UiccControlleronGetIccCardStatusDone() 方法:

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的源码中, 很多的使用观察者模式, 通过将 MessageHandler 进行注册其他的类中, 当前其他类的状态发生改变, 通过注册的 HandlerMessage 回调到进行注册的类, 此处我们需要查看该消息是在何处被注册的, 在 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));
            }
            ...
        }
    }
}

UiccControllermakeDefaultPhone() 的调用是在 PhoneGlobalsonCreate() 方法中

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);
        ...
    }
}

PhoneGlobalsonCreate() 被调用是在 PhoneApponCreate() 方法中

1.6. PhoneApponCreate() 方法

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);
    }
}

Android系统分析之运营商显示流程分析之运营商信息的读取流程二

上一篇:Android系统分析之运营商显示流程分析之运营商信息的获取和赋值一


下一篇:安卓开发HelloWorld