UICCcontroller 註冊監聽(RegistrantList)

主要講解RegistrantList的原理,以及如何快速分析RegistrantList相關的代碼流程。
在Telephony模塊中,在RIL、Tracker(ServiceStateTracker、CallTracker、DcTracker)、Phone(PhoneBase及其子類)、UICC框架、CallManager等等中都大量使用到的RegistrantList,可見RegistrantList使用範圍之廣。如果代碼流程中使用了RegistrantList,如何分析下一步代碼流程走到哪裏也是必須掌握的技能。

1 RegistrantList的原理
在講解RegistrantList之前,先引出觀察者模式的概念:
觀察者模式:定義對象間的一種一(Subject)對多(Observer)的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並且自動更新。

RegistrantList跟觀察者模式有點類似,先創建一個RegistrantList集合,專門關注某種消息;如果有人也對該消息感興趣的話,那麼爲他封裝一個Registrant對象並且添加到RegistrantList中;當有消息上報時,先通知RegistrantList,接着所有註冊到RegistrantList中的Registrant都會被通知到並且更新。
RegistrantList與Registrant的關係如下:
在這裏插入圖片描述
RegistrantList中有:
add()/addUnique()方法,用於增加一個Registrant;
remove()方法,用於刪除一個Registrant;
internalNotifyRegistrants()方法,用於通知所有的Registrant。

而Registrant中有:
internalNotifyRegistrants()方法,用於在收到RegistrantList的通知之後,再更新自己的內容。

2 UICCcontroller 註冊監聽卡狀態改變的實現方式
2.1 註冊監聽

在UiccController.java裏面實現狀態監控,UiccController的構造函數:

private UiccController(Context c, CommandsInterface ci) {
        mCi = ci;
        //註冊UICC卡狀態變化監聽
        mCi.registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, null);
        
        //註冊RADIO狀態變化監聽
        mCi.registerForOn(this, EVENT_ICC_STATUS_CHANGED, null);
        mCi.registerForAvailable(this, EVENT_ICC_STATUS_CHANGED, null);
        mCi.registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, null);
}

通過註冊registerForIccStatusChanged監聽,當moden向上傳來state 改變的消息,就會通知UiccController,使用handlermessage進行處理,在telephony源碼中,經常使用這種觀察者模式,下面以registerForIccStatesChanged爲例詳細分析註冊消息的發送以及接收。

3.2 registerForIccStatesChanged()方法的具體實現
在UICCcontroller.java中註冊一個事件監聽,當從moden往上層傳來的卡狀態變化時,通知handler做相應操作;
具體實現:
a. mIccStatusChangedRegistrants是通知者RegistrantList的一個對象,在BaseCommands.java中生成,並對通知者RegistrantList的添加、刪除做了封裝:

public void registerForIccStatusChanged(Handler h, int what, Object obj) {
        Registrant r = new Registrant (h, what, obj);
        mIccStatusChangedRegistrants.add(r);
}
@Override
public void unregisterForIccStatusChanged(Handler h) {
        mIccStatusChangedRegistrants.remove(h);
}
public  Registrant(Handler h, int what, Object obj)
{
        refH = new WeakReference(h);
        this.what = what;
        userObj = obj;
}

該構造方法中將Handler h, int what, Object obj這三個對象分別給了該Registrant對象的三個成員變量。並且,將該Registrant對象加入到mIccStatusChangedRegistrants的動態數組中去。
其中,add的方法的具體實現在RegistrantList.java:

public synchronized void add(Registrant r)
{
        removeCleared();
        registrants.add(r);
}

registrants是一個 ArrayList對象,管理Registrant其實就是對 ArrayList的操作。
在執行完成mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, index)方法後,表明UiccController已經向註冊了一個SIM卡的信息發生改變的消息,icc卡狀態變化這個監聽者就被註冊了,當icc state 變化的時候,mCallStateRegistrants就會通知調用的handler, UICCcontroller的handler msg進行處理。

b. 註冊以後,icc statue變化怎麼通知到通知到上層的:
在手機中,當ICC卡的狀態發生改變,Modem會向上傳遞消息,傳到framework時,被RIL.java接收處理,在處理請求的方法–processSolicited(上層主動請求,moden被動返回,這個時候,上層還需要給CP發送一個信息包) 和processUnsolicited(moden主動發出,一般上層的被動監聽都是通過這個方法來接受CP上來的主動消息)方法中調用notifyRegistrants來通知它所有的觀察者:

case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED:
                if (RILJ_LOGD) unsljLog(response);
                if (mIccStatusChangedRegistrants != null) {
                    mIccStatusChangedRegistrants.notifyRegistrants();
                }
                break;

mIccStatusChangedRegistrants是RegistrantList對象,notifyRegistrants的實現方法在RegistrantList.java,主要是遍歷之前存儲所有觀察者的ArrayList,然後sendmsg通知:

public void notifyRegistrants()
{
	internalNotifyRegistrants(null,Null);
}
private synchronized void internalNotifyRegistrants (Object result, Throwable exception)
{
       for (int i = 0, s = registrants.size(); i < s ; i++) {
            Registrant  r = (Registrant) registrants.get(i);
            r.internalNotifyRegistrant(result, exception);
       }
}

可以看到遍歷了mIccStatusChangedRegistrants中成員,遍歷動態數組中的Registrant。繼續追蹤Registrant.java中的執行情況:

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);
        }
}
Public Handler getHandler()
{
	if(refH == null)
return null;

return (Handler) refH.get();
}

這樣就完成了從RILJ到上層的消息註冊與通知,基本上在UICC上層的被動監聽接口都是這麼實現的,如下圖,RIL調用了CommandsInterface的接口,實現方法在BaseCommands。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章