UiccのUiccController(元)


UiccControllerは、UICCトランザクション全体のエントリであり、IccRecords、IccFileHandler、UIcCardApplicationなどのオブジェクトを外部に提供し、UICCシステム全体の初期化を完了します.
一、UiccControllerが提供する主な機能
私たちが提供するpublic方法を通じて、彼の主な機能を見てみましょう.
        public UiccCard getUiccCard() {}
        public UiccCardApplication getUiccCardApplication(int family) {}
        public IccRecords getIccRecords(int family) {}
        public IccFileHandler getIccFileHandler(int family) {}
        public void registerForIccChanged(Handler h, int what, Object obj) {}

上記の方法から分かるように、UiccControllerの主な役割は2つの面に現れている.
1.UiccCard、UiccCardApplication、IccRecords、IccFileHandlerなどのオブジェクトを作成して外部に提供する
2、SIM状態の傍受を提供する
二、UiccControllerの作成過程
まずUiccControllerがどこで作成されたかを見てみましょう.PhoneオブジェクトはPhoneモジュールの初期化でPhoneFactoryによって作成されたことを知っています.
        @PhoneGlobals.java
        public void onCreate() {
            if (phone == null) {
                //  Phone  
                PhoneFactory.makeDefaultPhones(this);
                //  Phone  
                phone = PhoneFactory.getDefaultPhone();
            }
        }
次にmakeDefaultPhones()のプロセスを見ます.
        @PhoneFactory.java
        public static void makeDefaultPhones(Context context) {
            makeDefaultPhone(context);
        }
        public static void makeDefaultPhone(Context context) { 
            //  RILJ
            sCommandsInterface = new RIL(context, networkMode, cdmaSubscription);
            //  UiccController
            UiccController.make(context, sCommandsInterface);
            //  phone Type
            int phoneType = TelephonyManager.getPhoneType(networkMode);
            //  PhoneProxy  
            if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
                sProxyPhone = new PhoneProxy(new GSMPhone(context, sCommandsInterface, sPhoneNotifier));
            } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
                switch (TelephonyManager.getLteOnCdmaModeStatic()) {
                    case PhoneConstants.LTE_ON_CDMA_TRUE:
                        sProxyPhone = new PhoneProxy(new CDMALTEPhone(context, sCommandsInterface, sPhoneNotifier));
                        break;
                    case PhoneConstants.LTE_ON_CDMA_FALSE:
                    default:
                        sProxyPhone = new PhoneProxy(new CDMAPhone(context, sCommandsInterface, sPhoneNotifier));
                        break;
                }
            }
        }
ここでは、newがRILオブジェクトを完了した後に、UiccControllerのmake()メソッドによってUiccControllerが作成され、渡された2つのパラメータのうちの1つがContextタイプオブジェクトであり、もう1つがCommandsInterfaceタイプのRILオブジェクトであることを示します.
次に、UiccControllerのmake()メソッドを使用して、特定の作成プロセスを見てみましょう.
        @UiccController.java
        public static UiccController make(Context c, CommandsInterface ci) {
            synchronized (mLock) {
                if (mInstance != null) {
                    throw new RuntimeException("UiccController.make() should only be called once");
                }
                mInstance = new UiccController(c, ci);
                return mInstance;
            }
        }
ここで注意すべきことは、UiccControllerのmake()メソッドは、一度だけ呼び出されます.つまり、グローバル全体で、
UiccControllerオブジェクトは1つのみ存在します.
        private UiccController(Context c, CommandsInterface ci) {
            mContext = c;
            mCi = ci;
            mCi.registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, null);
            mCi.registerForOn(this, EVENT_ICC_STATUS_CHANGED, null);
        }

UiccControllerのコンストラクション関数では、registerForIcccStatusChangedとregisterForOnの2つのリスナーを登録することしかできません.この2つのリスナーはSIMカードとRadioの状態を傍受しており、彼らはUiccController更新のトリガである.
三、UiccController更新メカニズム
        
先ほどお話ししたように、UiccControllerの初期化プロセスは主にRILJに2つのListenerを登録していますが、この2つのListenerはUiccController更新メカニズムのトリガであり、リスニングされたイベントが発生すると、UiccControllerはUICCフレームワーク全体の更新メカニズムを起動します.
具体的な更新手順を見てみましょう.
3.1.リスナーが傍受するイベント
3.1.1.registerForIccStatusChangedリスナー
registerForIccStatusChangedという登録の動作は、RILクラスに直接呼び出されるのではなく、RILの親BaseCommandsに呼び出されます.
        @BaseCommands.java
        public void registerForIccStatusChanged(Handler h, int what, Object obj) {
            Registrant r = new Registrant (h, what, obj);
            mIccStatusChangedRegistrants.add(r);
        }
ここでの登録プロセスは、mIcccStatusChangedRegistrantsオブジェクトリストに現在の登録オブジェクトを追加し、次の2つのイベントが発生すると、リスト内のリスナーに通知されます.
       
1、誤ったPINまたはPUKを入力した場合:
        private RILRequest processSolicited (Parcel p) {
            switch (rr.mRequest) {
                case RIL_REQUEST_ENTER_SIM_PUK:
                case RIL_REQUEST_ENTER_SIM_PUK2:
                    if (mIccStatusChangedRegistrants != null) {
                        mIccStatusChangedRegistrants.notifyRegistrants();
                    }
                    break;
            }
        }
        
2、SIMカードの状態が変化した場合:
        private void processUnsolicited (Parcel p) {
            switch(response) {
                case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED:
                    if (mIccStatusChangedRegistrants != null) {
                        mIccStatusChangedRegistrants.notifyRegistrants();
                    }
                    break;
            }
        }

3.1.2、registerForOnリスナーはregisterForIccStatusChangedと類似しており、registerForOn()もBaseCommandsで実現されている.
        @BaseCommands.java
        public void registerForOn(Handler h, int what, Object obj) {
            Registrant r = new Registrant (h, what, obj);
            synchronized (mStateMonitor) {
                //        mOnRegistrants   
                mOnRegistrants.add(r);
                if (mState.isOn()) {
                    r.notifyRegistrant(new AsyncResult(null, null, null));
                }
            }
        }
登録のプロセスは、mOnRegistrants変数のリストにリスナー情報を保存し、次の2つのイベントが発生するとリストを巡回してリスナーに通知することです.
       
1、Radio状態が変化した場合:
        private void processUnsolicited (Parcel p) {
            switch(response) {
                case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED:
                    RadioState newState = getRadioStateFromInt(p.readInt());
                    switchToRadioState(newState);
                    break;
            }
        }
        private void switchToRadioState(RadioState newState) {
            setRadioState(newState);
        }
        protected void setRadioState(RadioState newState) {
            synchronized (mStateMonitor) {
                //     
                mRadioStateChangedRegistrants.notifyRegistrants();
            }
        }
        
2、RILJとRILC通路が切り離された場合
        class RILReceiver implements Runnable {
            @Override
            public void run() {
                //Socket    ,  Radio   unavailable  
                setRadioState (RadioState.RADIO_UNAVAILABLE);
            }
        }

上記の分析から、RILは、以下のイベントが発生すると、現在のUIcControllerに通知を開始することがわかります.
1、入力エラーのPIN、PUKコード2、SIMカード状態変化3、Radio状態変化4、Socketチャネルオフ
次に、UiccControllerの動作を確認します.
3.2.UiccControllerによるリスニングイベントの処理フローUiccControllerが上記の2種類のリスナーを登録する際に使用するwhatパラメータはいずれも「EVENT_ICC_STATUS_CHANGED」であるため、上記リスニングイベントが発生した場合、いずれも同じEVENT_ICC_STATUS_CHANGEDのcaseブランチ:
        @UiccController.java
        public void handleMessage (Message msg) {
            synchronized (mLock) {
                switch (msg.what) {
                    case EVENT_ICC_STATUS_CHANGED:
                        //   SIM      Radio       ,     case 
                        mCi.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
                        break;
                    case EVENT_GET_ICC_STATUS_DONE:
                        AsyncResult ar = (AsyncResult)msg.obj;
                        onGetIccCardStatusDone(ar);
                        break;
                    default:
                        Rlog.e(LOG_TAG, " Unknown Event " + msg.what);
                }
            }
        }
はRILを呼び出す.JAvaのgetIccCardStatus()メソッドは、最新のSIMとRadio状態をクエリーします.
RILJがgetIccCardStatus()のリクエストを取得すると、Modemに現在のSIMカードのステータスを問い合わせるリクエストが開始されます.
        @RIL.java
        public void getIccCardStatus(Message result) {
            // Modem    ,     SIM   
            RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_SIM_STATUS, result);
            send(rr);
        }
そして最新の状態を取得した後、結果を開始要求の対象にフィードバックします.現在はUiccControllerです.
        private RILRequest processSolicited (Parcel p) {
            switch (rr.mRequest) {
                case RIL_REQUEST_GET_SIM_STATUS: 
                    //  Modem        IccCardStatus  
                    ret =  responseIccCardStatus(p); break;
            }
            if (rr.mResult != null) {
                AsyncResult.forMessage(rr.mResult, ret, null);
                //      UiccController
                rr.mResult.sendToTarget();
            }
        }
続いて、UiccControllerは再びhandleMessage()メソッドで次の流れを処理しますが、今回入ったのはEVENT_です.GET_ICC_STATUS_DONEのケースフロー:
        @UiccController.java
        public void handleMessage (Message msg) {
            synchronized (mLock) {
                switch (msg.what) {
                    case EVENT_ICC_STATUS_CHANGED:
                        //        ,    
                        mCi.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
                        break;
                    case EVENT_GET_ICC_STATUS_DONE:
                        //     SIM   
                        AsyncResult ar = (AsyncResult)msg.obj;
                        onGetIccCardStatusDone(ar);
                        break;
                    default:
                        Rlog.e(LOG_TAG, " Unknown Event " + msg.what);
                }
            }
        }
UiccControllerの最新状態に対する処理を引き続き見る:
        private synchronized void onGetIccCardStatusDone(AsyncResult ar) {
            if (ar.exception != null) {
                return;
            }
            //  RIL    IccCardStatus  
            IccCardStatus status = (IccCardStatus)ar.result;

            //     UiccCard
            if (mUiccCard == null) {
                mUiccCard = new UiccCard(mContext, mCi, status);
            } else {
                mUiccCard.update(mContext, mCi , status);
            }
            //           
            mIccChangedRegistrants.notifyRegistrants();
        }
ここでは、UiccControllerが最新のSIMカードのステータスを取得した後、2つのことをしました.
1、UiccCardを作成または更新する;2.他のサブリスナーに通知する.
また、2つの情報を取得しました.1、UiccCardオブジェクトは、UiccControllerがSIMカードの状態を更新したときに作成されます.2、その他のオブジェクトはregisterForIccChanged()メソッドでUIcControllerにSIMカードのステータスリスニングを申請することができる.
これで、UiccControllerの解析は終了し、次の章ではUiccCardオブジェクトについて説明します.