zoukankan      html  css  js  c++  java
  • 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);
        }
    }
  • 相关阅读:
    python中的 upper() 、lower()、capitalize()、title()方法
    python中的strip()函数的用法
    python中的split()函数的用法
    python中的join()函数的用法
    appium 简单的测试例子(1)
    模拟器连接使用
    appuim连接时的一些出现的错误
    android获取包名的几种方法
    python+Appium(1)
    专注基础软件自研,巨杉入选“2020信创产业独角兽100强”
  • 原文地址:https://www.cnblogs.com/firmly-believe/p/10764406.html
Copyright © 2011-2022 走看看