SIM卡 框架分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lf12345678910/article/details/54375025

CPHS service :卡内嵌入服务指令

* Once created UiccController registers with RIL for "on" and "unsol_sim_status_changed"
 * notifications. When such notification arrives UiccController will call
 * getIccCardStatus (GET_SIM_STATUS). Based on the response of GET_SIM_STATUS
 * request appropriate tree of uicc objects will be created.
 *

 * Following is class diagram for uicc classes:
 *
 *                       UiccController
 *                            #
 *                            |
 *                        UiccCard
 *                          #   #
 *                          |   ------------------
 *                    UiccCardApplication    CatService
 *                      #            #
 *                      |            |
 *                 IccRecords    IccFileHandler
 *                 ^ ^ ^           ^ ^ ^ ^ ^
 *    SIMRecords---- | |           | | | | ---SIMFileHandler
 *    RuimRecords----- |           | | | ----RuimFileHandler
 *    IsimUiccRecords---           | | -----UsimFileHandler
 *                                 | ------CsimFileHandler
 *                                 ----IsimFileHandler
 *
 * Legend: # stands for Composition
 *         ^ stands for Generalization

Android4.4 Telephony流程分析——SIM卡开机时的初始化

http://blog.csdn.net/canghai1129/article/details/41011527

PhoneApp作为Android系统中首屈一指的Application,其在创建的时候会构造出对整个系统来说至关重要的ril.java的实体,在这个rilj构造出来后,会与底层的rild connect上,并且连通他们之间通信的socket,这样手机的通话、短信功能才可用;

PhoneApp如此重要和基础,其是在哪里被创建出来的呢

在ActivityManagerService.java里的 SystemReady函数的最后有以下代码

加粗的函数getPersistentApplications可以get到phoneapp的info,然后使用函数addAppLocked把PhoneApp启动起来

    <application在ActivityManagerService.java里的 SystemReady函数的最后有以下代码 android:name="PhoneApp"
            android:persistent="true"

packages/services/Telephony/src/com/android/phone/PhoneApp.java

onCreate(

            // We are running as the primary user, so should bring up the
            // global phone state.

//这里是我们关注的,数据和语音所需的基础类在这里创建

            mPhoneGlobals = new PhoneGlobals(this);
            mPhoneGlobals.onCreate();

网上的参考信息是处理PSTN呼叫

            mTelephonyGlobals = new TelephonyGlobals(this);
            mTelephonyGlobals.onCreate();

)

packages/services/Telephony/src/com/android/phone/PhoneGlobals.java

    CallController callController;
    CallManager mCM;
    CallNotifier notifier;
    CallerInfoCache callerInfoCache;
    NotificationMgr notificationMgr;
    public PhoneInterfaceManager phoneMgr;
    public SimActivationManager simActivationManager;
    CarrierConfigLoader configLoader;

    private CallGatewayManager callGatewayManager;
    private Phone phoneInEcm;

onCreate(

            // Initialize the telephony framework
            PhoneFactory.makeDefaultPhones(this);

)

frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneFactory.java

//初始化phone与ril、UiccController、TelephonyNetworkFactory的关系// phone 都为GsmCdmaPhone

makeDefaultPhone(   

sUiccController = UiccController.make(context, sCommandsInterfaces);

)

rild主动上报射频信号状态

RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED

GsmServiceStateTracker(更新网络状态)、SIMRecords(用IccFileHandler读取SIM卡内置紧急号码)和SIMRecordsEx(向RILD查询20位的Iccid)

所以总结来看,UiccController就是通过向RIL注册卡状态变化的监听,当底层一有变化时,会通过RIL上报给UiccController,这样就会触发其下发getIccCardStatus来查询卡状态,得到卡状态后更新其内部的UiccCard及UIccCardApplication等。所以phone或者其他state tracker service可以通过UiccController来获取到正确的卡信息

frameworks/opt/telephony/

UiccController.java

    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);
            mCis[i].registerForAvailable(this, EVENT_ICC_STATUS_CHANGED, index);
            mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, index);
            mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, index);
        }
    }

handleMessage(

            switch (msg.what) {
                case EVENT_ICC_STATUS_CHANGED:
                    if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus");
                    mCis[index].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, index));
                    break;

                case EVENT_GET_ICC_STATUS_DONE:
                    if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");
                    onGetIccCardStatusDone(ar, index);
                    break;

)

onGetIccCardStatusDone(

        if (mUiccCards[index] == null) {
            //Create new card
            mUiccCards[index] = new UiccCard(mContext, mCis[index], status, index);
        } else {
            //Update already existing card
            mUiccCards[index].update(mContext, mCis[index] , status);
        }

        if (DBG) log("Notifying IccChangedRegistrants");
        mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));

)

registerForIccChanged(mIccChangedRegistrants.add(r))

frameworks/opt/telephony/

UiccCard.java

update(mUiccApplications[i] = new UiccCardApplication(this,ics.mApplications[i], mContext, mCi);)

frameworks/opt/telephony/

UiccCardApplication.java

mIccRecords = createIccRecords(as.app_type, mContext, mCi);

frameworks/opt/telephony/

SIMRecords.java

        mAdnCache = new AdnRecordCache(mFh);
        mVmConfig = new VoiceMailConstants();
        mSpnOverride = new SpnOverride();

 

frameworks/opt/telephony/

BaseCommands.java

registerForIccStatusChanged()

frameworks/opt/telephony/

RIL.java

processSolicited(

 case RIL_REQUEST_ENTER_SIM_PUK:
 case RIL_REQUEST_ENTER_SIM_PUK2:

 case RIL_REQUEST_ENTER_SIM_PIN:
 case RIL_REQUEST_ENTER_SIM_PIN2:
 case RIL_REQUEST_CHANGE_SIM_PIN:
 case RIL_REQUEST_CHANGE_SIM_PIN2:
 case RIL_REQUEST_SET_FACILITY_LOCK:

case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED:

mIccStatusChangedRegistrants.notifyRegistrants();

)

/packages/services/Telephony/src/com/android/services/telephony/

TelephonyGlobals.java

onCreate( TelecomAccountRegistry.getInstance(mContext).setupOnBoot(); )

packages/services/telephony

//拥有我们在通信时注册的所有数据,包括处理动态添加和删除SIM和SIP帐户。

TelecomAccountRegistry.java

    /**
     * Sets up all the phone accounts for SIMs on first boot.
     */
    void setupOnBoot() {
        // TODO: When this object "finishes" we should unregister by invoking
        // SubscriptionManager.getInstance(mContext).unregister(mOnSubscriptionsChangedListener);
        // This is not strictly necessary because it will be unregistered if the
        // notification fails but it is good form.

        // Register for SubscriptionInfo list changes which is guaranteed
        // to invoke onSubscriptionsChanged the first time.
        SubscriptionManager.from(mContext).addOnSubscriptionsChangedListener(
                mOnSubscriptionsChangedListener);

        // We also need to listen for changes to the service state (e.g. emergency -> in service)
        // because this could signal a removal or addition of a SIM in a single SIM phone.
        mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
    }
 

    private OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
            new OnSubscriptionsChangedListener() {
        @Override
        public void onSubscriptionsChanged() {
            // Any time the SubscriptionInfo changes...rerun the setup
            tearDownAccounts();
            setupAccounts();
        }
    };

    private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
        @Override
        public void onServiceStateChanged(ServiceState serviceState) {
            int newState = serviceState.getState();
            if (newState == ServiceState.STATE_IN_SERVICE && mServiceState != newState) {
                tearDownAccounts();
                setupAccounts();
            }
            mServiceState = newState;
        }
    };

-----------------------------------------------------------------------------------------------------

frameworks/base/telephony

SubscriptionManager.java

addOnSubscriptionsChangedListener(

 try {
            // We use the TelephonyRegistry as it runs in the system and thus is always
            // available. Where as SubscriptionController could crash and not be available
            ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
                    "telephony.registry"));
            if (tr != null) {
                tr.addOnSubscriptionsChangedListener(pkgForDebug, listener.callback);
            }

)

frameworks/base/services

TelephonyRegistry.java

addOnSubscriptionsChangedListener(mRecords.add(r); )

notifySubscriptionInfoChanged(

for (Record r : mRecords) {

r.onSubscriptionsChangedListenerCallback.onSubscriptionsChanged();}

)

frameworks/opt/telephony/src/java/com/android/internal/telephony/

SubscriptionController.java

     public void notifySubscriptionInfoChanged() {
         ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
                 "telephony.registry"));
         try {
             if (DBG) logd("notifySubscriptionInfoChanged:");
             tr.notifySubscriptionInfoChanged();
         } catch (RemoteException ex) {
             // Should never happen because its always available.
         }

         // FIXME: Remove if listener technique accepted.
         broadcastSimInfoContentChanged();
     }

setCarrierText( notifySubscriptionInfoChanged(); )

 /**
     * Generate and set carrier text based on input parameters
     * @param showPlmn flag to indicate if plmn should be included in carrier text
     * @param plmn plmn to be included in carrier text
     * @param showSpn flag to indicate if spn should be included in carrier text
     * @param spn spn to be included in carrier text
     * @return true if carrier text is set, false otherwise
     */
    public boolean setPlmnSpn(int slotId, boolean showPlmn, String plmn, boolean showSpn,
                              String spn) {

setCarrierText(carrierText, subIds[i]);

}

frameworks/opt/telephony/src/java/com/android/internal/telephony/

ServiceStateTracker.java

initOnce(

    mSubscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);

)

updateSpnDisplay(){

然后回到updateSpnDisplay()方法中,此时将会通过mSS.getOperatorAlphaLong()得到当前的PLMN值,以及通过rule得到当前是否需要显示PLMN(showPlmn),然后通过iccRecords.getServiceProviderName()得到当前的SPN以及通过rule得到当前是否需要显示SPN。

}

onSubscriptionsChanged()

private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (!mPhone.isPhoneTypeGsm()) {
                loge("Ignoring intent " + intent + " received on CDMA phone");
                return;
            }

            if (intent.getAction().equals(Intent.ACTION_LOCALE_CHANGED)) {//系统语言切换
                // update emergency string whenever locale changed
                updateSpnDisplay();
            } else if (intent.getAction().equals(ACTION_RADIO_OFF)) {
                mAlarmSwitch = false;
                DcTracker dcTracker = mPhone.mDcTracker;
                powerOffRadioSafely(dcTracker);
            }
        }
    };

--------------------------------------------------------------------------------------------------------

frameworks/base/telephony

TelephonyManager.java

public void listen(PhoneStateListener listener, int events) {
            sRegistry.listenForSubscriber(listener.mSubId, getOpPackageName(),
                    listener.callback, events, notifyNow);

}

frameworks/base/service

TelephonyRegistry.java

listenForSubscriber(boolean notifyNow)

listen(  //notifyNow 立即通知

mRecords.add(r);

r.callback.onServiceStateChanged

r.callback.onSignalStrengthChanged

r.callback.onCallStateChanged

r.callback.onDataConnectionStateChanged

r.callback.onDataActivity

r.callback.onSignalStrengthsChanged

r.callback.onCarrierNetworkChange

.............................

)

notifyServiceStateForPhoneId(

r.callback.onServiceStateChanged(new ServiceState(state));

 broadcastServiceStateChanged(state, phoneId, subId);

)

frameworks/opt/telephony/src/java/com/android/internal/telephony/

DefaultPhoneNotifier.java

notifyServiceState( mRegistry.notifyServiceStateForPhoneId(phoneId, subId, ss); )

frameworks/opt/telephony/src/java/com/android/internal/telephony/

Phone.java

notifyServiceStateChangedP( mNotifier.notifyServiceState(this); )

frameworks/opt/telephony/src/java/com/android/internal/telephony/

GsmCdmaPhone.java

    public void notifyServiceStateChanged(ServiceState ss) {
        super.notifyServiceStateChangedP(ss);
    }

frameworks/opt/telephony/src/java/com/android/internal/telephony/

ServiceStateTracker.java

initOnce(

mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);

)

updateRilImsRadioTechnology( mPhone.notifyServiceStateChanged(mSS);)

pollStateDoneGsm( mPhone.notifyServiceStateChanged(mSS); )

pollStateDoneCdma( mPhone.notifyServiceStateChanged(mSS); )

pollStateDoneCdmaLte( mPhone.notifyServiceStateChanged(mSS); )

    //todo: try to merge pollstate functions
    private void pollStateDone() {
        if (mPhone.isPhoneTypeGsm()) {
            pollStateDoneGsm();
        } else if (mPhone.isPhoneTypeCdma()) {
            pollStateDoneCdma();
        } else {
            pollStateDoneCdmaLte();
        }
    }

handlePollStateResult(

 pollStateDone()

)

pollState(

        switch (mCi.getRadioState()) {
            case RADIO_UNAVAILABLE:
                mNewSS.setStateOutOfService();
                mNewCellLoc.setStateInvalid();
                setSignalStrengthDefaultValues();
                mGotCountryCode = false;
                mNitzUpdatedTime = false;
                pollStateDone();
                break;

            case RADIO_OFF:
                mNewSS.setStateOff();
                mNewCellLoc.setStateInvalid();
                setSignalStrengthDefaultValues();
                mGotCountryCode = false;
                mNitzUpdatedTime = false;
                // don't poll for state when the radio is off
                // EXCEPT, if the poll was modemTrigged (they sent us new radio data)
                // or we're on IWLAN
                if (!modemTriggered && ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
                        != mSS.getRilDataRadioTechnology()) {
                    pollStateDone();
                    break;
                }

)

handleMessage(){

            case EVENT_SIM_READY:
                // Reset the mPreviousSubId so we treat a SIM power bounce
                // as a first boot.  See b/19194287
                mOnSubscriptionsChangedListener.mPreviousSubId.set(-1);
                pollState();
                // Signal strength polling stops when radio is off
                queueNextSignalStrengthPoll();
                break;

            case EVENT_ICC_CHANGED:
                onUpdateIccAvailability();

}

onUpdateIccAvailability(

mUiccApplcation.registerForReady(this, EVENT_SIM_READY, null);

)

frameworks/opt/telephony

UiccCardApplication.java

    public void registerForReady(Handler h, int what, Object obj) {
        synchronized (mLock) {
            Registrant r = new Registrant (h, what, obj);
            mReadyRegistrants.add(r);
            notifyReadyRegistrantsIfNeeded(r);
        }
    }

notifyReadyRegistrantsIfNeeded( mReadyRegistrants.notifyRegistrants(); )

update(

                notifyPinLockedRegistrantsIfNeeded(null);
                notifyReadyRegistrantsIfNeeded(null);

)

猜你喜欢

转载自blog.csdn.net/lf12345678910/article/details/54375025