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

前面有说过,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的handleMessage,而且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加载完成





 

你可能感兴趣的:(SIM卡开机流程分析)