從手機來電分析android訊息機制

來源:互聯網
上載者:User
當RIL收到這個訊息UNSOL_CALL_RING然後調用mRingRegistrant.notifyRegistrant(new AsyncResult (null, ret, null));mRingRegistrant是在哪裡註冊的呢?在BaseCommands.java通過這個方法註冊的:    public void setOnCallRing(Handler h, int what, Object obj) {        mRingRegistrant = new Registrant (h, what, obj);    }setOnCallRing這個方法在phoneBase.java的建構函式種通過:    mCM.setOnCallRing(this, EVENT_CALL_RING, null);ok,所以,此時,handleMessage處理EVENT_CALL_RING訊息,然後調用sendIncomingCallRingNotification()在這個方法裡面,做兩件事情:    notifyIncomingRing();    sendMessageDelayed(obtainMessage(EVENT_CALL_RING_CONTINUE, token, 0), mCallRingDelay);後面的方法作用是用來迴圈播放鈴聲的。延遲多少秒具體各手機廠商不同。繼續:notifyIncomingRing()方法裡面主要是啟用這個註冊訊息:    mIncomingRingRegistrants.notifyRegistrants(ar);ok,我們繼續看mIncomingRingRegistrants是在哪裡註冊的,可以看出是phoneBase.java註冊的    public void registerForIncomingRing(            Handler h, int what, Object obj) {        checkCorrectThread(h);        mIncomingRingRegistrants.addUnique(h, what, obj);        }checkCorrectThread這個方法主要是為了驗證當前的線程是不是和原來的線程保持一直,如果不是,拋出異常registerForIncomingRing這個方法是callManager.java註冊的     phone.registerForIncomingRing(mHandler, EVENT_INCOMING_RING, null);收到訊息後,然後處理EVENT_INCOMING_RING    case EVENT_INCOMING_RING:                    if (!hasActiveFgCall()) {                        mIncomingRingRegistrants.notifyRegistrants((AsyncResult) msg.obj);                    }                    break;然後判斷當前有沒有前台call,如果有,停止處理,如果沒有,繼續....mIncomingRingRegistrants是在callManagar.java    public void registerForIncomingRing(Handler h, int what, Object obj){        mIncomingRingRegistrants.addUnique(h, what, obj);        }然後registerForIncomingRing是在phoneapp種的callNotifier.java中註冊:    mCM.registerForIncomingRing(this, PHONE_INCOMING_RING, null);所以,最終到了phoneapp中的這裡,然後phoneApp處理PHONE_INCOMING_RING訊息,調用:mRinger.ring()完成響鈴和迴圈響鈴的工作;當然,來點的時候,這個訊息只是其中訊息的一個,僅僅是為了完成響鈴而來的訊息。下一步啟動phone的訊息,是一個叫UNSOL_RESPONSE_CALL_STATE_CHANGED 的訊息,處理機制和上面的一致,其實,FW層基本上都是這種套路,沒什麼特別。這個架構非常好,各層之間低耦合,很不錯。ok,其實上面說的都是廢話,這篇文章,其實我主要是想藉助這一個訊息,來說說RegistrantList這個類是如何來管理各種訊息之間的不斷添加和被啟用的。上面文章談到的那些mIncomingRingRegistrants都是RegistrantList.其實,說白了,這個RegistrantList就是Registrant的集合,字面意思Registrant是個什麼東東?哎,登記的意思,就是你要幹什麼活,先來人才中心登記下,等活來了,發現是你需要的,好,我通知你來幹活。Registrant本質上是個什麼東東?其實就是handle 和message的組合體。具體如下:首先我們看到RegistrantList裡面添加訊息方法:public synchronized void    addUnique(Handler h, int what, Object obj)    {        // if the handler is already in the registrant list, remove it        remove(h);        add(new Registrant(h, what, obj));            }首先移除當前的handler,如果它存在當前的list中的話。然後把當前的訊息和handler添加到RegistrantList中去,RegistrantList是個ArrayList.對於這個add方法:public synchronized void    add(Registrant r)    {        removeCleared(); //        registrants.add(r);    }上面的removeCleared()方法內容如下: public synchronized void    removeCleared()    {        for (int i = registrants.size() - 1; i >= 0 ; i--) {            Registrant  r = (Registrant) registrants.get(i);                        if (r.refH == null) {                registrants.remove(i);            }        }    }可以看出其實這個方法就是移除ArrayList中的沒有指定的handler的Registrant的。r.refH 是一個java中的WeakRreference弱引用對象。什麼事弱引用呢?簡單點,就是可以儲存某對象的訊息,又不影響他的回收。好,繼續,上面的代碼先清除掉,然後添加到ArrayList中去儲存。ok, 在ril中mRingRegistrant.notifyRegistrant(new AsyncResult (null, ret, null));後,調用:public /*synchronized*/ void    notifyRegistrants(AsyncResult ar)    {        internalNotifyRegistrants(ar.result, ar.exception);    }然後  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);       }    }可以看出目前是在從ArrayList中取出所有的registrants,然後給觸發他們處理訊息。從這裡可以看出,我們可以為同一個ArrayList裡面添加幾個registrants,添加不同的what參數,然後在這裡都會被觸發啟用。回到上面方法的r.internalNotifyRegistrant(result, exception);/*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);        }    }其實,先不看這個方法,我們前面看到了,我們在add訊息的時候add(new Registrant(h, what, obj));是把訊息封裝成Registrant對象儲存起來了。看Registrant的構造方法:public    Registrant(Handler h, int what, Object obj)    {        refH = new WeakReference(h);        this.what = what;        userObj = obj;    }把當前的handler儲存到弱引用中,待會可以通過get()方法拿到。然後把訊息值等也儲存起來。然後,上面的方法internalNotifyRegistrant 中,我們可以看到第一步通過getHandler()方法獲得Handler對象public Handler    getHandler()    {        if (refH == null)            return null;        return (Handler) refH.get(); //這裡大家看明白了吧,前面說了的。    }如果handler不存咋,調用clear方法清除。反之,通過訊息機制,發送訊息給這個訊息歸屬的handler處理,其實,就是前面的callNotifier.java並且帶上PLD返回來的AsyncResult訊息。Message msg = Message.obtain(); //一般獲得訊息都是通過這個方法,不是直接執行個體化,因為這個方法可以避免重複建立            msg.what = what;                        msg.obj = new AsyncResult(userObj, result, exception);                        h.sendMessage(msg);哎,都說到這裡了,順便說說android的handler機制吧首先,需要明白一些訊息機制的概念:Looper:一條線程可以產生一個looper對象,有他來管理此線程的messageQueue訊息佇列Handler:咱們可以構造Handler對象來與Looper溝通,以便push新訊息到MessageQueue裡面,或者接受Looper從訊息佇列裡面送出來的訊息。MessageQueue: 訊息佇列,用來存放線程中放入的訊息。線程:不講什麼UI線程了,網上很多,自己去看,普及下知識,什麼是線程?線程就是一段代碼邏輯從前到後的執行路徑,新開條線程,相當於有兩條路徑可以走ok,下面開始介紹android的handler和message機制ok,大家平常聽到的什麼UI線程,大家可以去看activity的源碼,在activity初始化的時候,就會有ActivityThread.java來建立主線程,在activity中建立looper和messageQueue對象等。這部分就不分析了,大家自己看看就行了。我分析的,僅限於當前的case首先h.sendMessage(msg);我們看這個方法:(當然,這個msg裡麵包含了pld返回的object還有我們訊息標誌的what資訊)     /**     * Pushes a message onto the end of the message queue after all pending messages     * before the current time. It will be received in {@link #handleMessage},     * in the thread attached to this handler.     *       * @return Returns true if the message was successfully placed in to the      *         message queue.  Returns false on failure, usually because the     *         looper processing the message queue is exiting.     */    public final boolean sendMessage(Message msg)    {        return sendMessageDelayed(msg, 0);    }繼續:    public final boolean sendMessageDelayed(Message msg, long delayMillis)    {        if (delayMillis < 0) { //判斷小於0,不做處理            delayMillis = 0;        }        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);    }繼續handler.java/**     * Enqueue a message into the message queue after all pending messages     * before the absolute time (in milliseconds) <var>uptimeMillis</var>.     * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>     * You will receive it in {@link #handleMessage}, in the thread attached     * to this handler.     *      * @param uptimeMillis The absolute time at which the message should be     *         delivered, using the     *         {@link android.os.SystemClock#uptimeMillis} time-base.     *              * @return Returns true if the message was successfully placed in to the      *         message queue.  Returns false on failure, usually because the     *         looper processing the message queue is exiting.  Note that a     *         result of true does not mean the message will be processed -- if     *         the looper is quit before the delivery time of the message     *         occurs then the message will be dropped.     */    public boolean sendMessageAtTime(Message msg, long uptimeMillis)    {        boolean sent = false;        MessageQueue queue = mQueue; //這個mQueue待會再說        if (queue != null) { //如果訊息佇列有,就把當前的handler對象給target,並把訊息給訊息佇列            msg.target = this;            sent = queue.enqueueMessage(msg, uptimeMillis);        }        else {            RuntimeException e = new RuntimeException(                this + " sendMessageAtTime() called with no mQueue");            Log.w("Looper", e.getMessage(), e);        }        return sent;    }前提咱們必須知道的是,一條線程最多隻有一個looper和一個messageQueue。這裡,我們要知道mQueue是從哪裡來的?其實,應該能猜到,肯定要構造傳進來啊看handler的構造方法:     /**     * Default constructor associates this handler with the queue for the     * current thread.     *     * If there isn't one, this handler won't be able to receive messages.     */    public Handler() {        if (FIND_POTENTIAL_LEAKS) {            final Class<? extends Handler> klass = getClass();            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&                    (klass.getModifiers() & Modifier.STATIC) == 0) {                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +                    klass.getCanonicalName());            }        }        mLooper = Looper.myLooper(); //獲得當前線程的looper對象        if (mLooper == null) {            throw new RuntimeException(                "Can't create handler inside thread that has not called Looper.prepare()");        }        mQueue = mLooper.mQueue;     //從looper對象中擷取它管理的messageQueue        mCallback = null;    }從looper物件建構方法可以看出:private Looper() {        mQueue = new MessageQueue();  //執行個體化當前的messageQueue對象        mRun = true;        mThread = Thread.currentThread();  //取得當前線程    }哈哈,懂了吧,最後看個方法,看訊息如何存到messageQueue中的    final boolean enqueueMessage(Message msg, long when) {        if (msg.isInUse()) {            throw new AndroidRuntimeException(msg                    + " This message is already in use.");        }        if (msg.target == null && !mQuitAllowed) {            throw new RuntimeException("Main thread not allowed to quit");        }        final boolean needWake;        synchronized (this) {            if (mQuiting) {                RuntimeException e = new RuntimeException(                    msg.target + " sending message to a Handler on a dead thread");                Log.w("MessageQueue", e.getMessage(), e);                return false;            } else if (msg.target == null) {                mQuiting = true;            }            msg.when = when;            //Log.d("MessageQueue", "Enqueing: " + msg);            Message p = mMessages;            if (p == null || when == 0 || when < p.when) {                msg.next = p;  //好熟悉好熟悉啊,這個next肯定是message對象,百分之百,java實現鏈表資料結構就是這麼寫的啊,看來基礎真的很重要                mMessages = msg;                needWake = mBlocked; // new head, might need to wake up            } else {                Message prev = null;                while (p != null && p.when <= when) {                    prev = p;                    p = p.next;                }                msg.next = prev.next;                prev.next = msg;                needWake = false; // still waiting on head, no need to wake up            }        }        if (needWake) {            nativeWake(mPtr);        }        return true;    }其實上面的方法就是把一個一個的message對象通過java鏈表的方式給串起來。ok,訊息已經放到訊息佇列裡面去了,那怎麼取出來?什麼時候取出來?如何取出來?取出來給誰?首先,我們要明白activity啟動的流程。簡單的說,是ActivityThread.java在做一系列的操作。每個應用程式都以ActivityThread.main()為入口進入到訊息迴圈處理。對於一個進程來講,我們需要這個閉合的處理架構。ActivitiyThread是應用程式概念空間的重要概念,他建立了應用進程啟動並執行架構,並提供了一個IActivityThread介面作為與 Activity Manager Service的通訊介面.通過該介面ActivityManagerService可以將Activity的狀態變化傳遞到用戶端的Activity對象。在ActivityThread.java的main入口方法中:public static void main(String[] args) {        SamplingProfilerIntegration.start();        // CloseGuard defaults to true and can be quite spammy.  We        // disable it here, but selectively enable it later (via        // StrictMode) on debug builds, but using DropBox, not logs.        CloseGuard.setEnabled(false);        Process.setArgV0("<pre-initialized>");        Looper.prepareMainLooper();        if (sMainThreadHandler == null) {            sMainThreadHandler = new Handler();        }        ActivityThread thread = new ActivityThread();        thread.attach(false);        if (false) {            Looper.myLooper().setMessageLogging(new                    LogPrinter(Log.DEBUG, "ActivityThread"));        }        Looper.loop();        throw new RuntimeException("Main thread loop unexpectedly exited");    }調用了當前線程的Looper.loop()方法迴圈從messageQueue中取出訊息處理:  /**     * Run the message queue in this thread. Be sure to call     * {@link #quit()} to end the loop.     */    public static void loop() {        Looper me = myLooper();        if (me == null) {            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");        }        MessageQueue queue = me.mQueue;                // Make sure the identity of this thread is that of the local process,        // and keep track of what that identity token actually is.        Binder.clearCallingIdentity();        final long ident = Binder.clearCallingIdentity();                while (true) {            Message msg = queue.next(); // might block            if (msg != null) {                if (msg.target == null) {                    // No target is a magic identifier for the quit message.                    return;                }                long wallStart = 0;                long threadStart = 0;                // This must be in a local variable, in case a UI event sets the logger                Printer logging = me.mLogging;                if (logging != null) {                    logging.println(">>>>> Dispatching to " + msg.target + " " +                            msg.callback + ": " + msg.what);                    wallStart = SystemClock.currentTimeMicro();                    threadStart = SystemClock.currentThreadTimeMicro();                }                msg.target.dispatchMessage(msg);                if (logging != null) {                    long wallTime = SystemClock.currentTimeMicro() - wallStart;                    long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;                    logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);                    if (logging instanceof Profiler) {                        ((Profiler) logging).profile(msg, wallStart, wallTime,                                threadStart, threadTime);                    }                }                // Make sure that during the course of dispatching the                // identity of the thread wasn't corrupted.                final long newIdent = Binder.clearCallingIdentity();                if (ident != newIdent) {                    Log.wtf(TAG, "Thread identity changed from 0x"                            + Long.toHexString(ident) + " to 0x"                            + Long.toHexString(newIdent) + " while dispatching to "                            + msg.target.getClass().getName() + " "                            + msg.callback + " what=" + msg.what);                }                                msg.recycle();            }        }    }可以,看出,此loop方法是個死迴圈,通過queue.next()取出訊息後,然後通過handler的方法發送出去從前面看出,那個給message的target就是handler。前面傳入的然後通過msg.target.dispatchMessage(msg);方法分發訊息handler.java:    /**     * Handle system messages here.     */    public void dispatchMessage(Message msg) {        if (msg.callback != null) {            handleCallback(msg);        } else {            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {                    return;                }            }            handleMessage(msg);        }    }callback預設為空白,因為不是自己new出的線程,沒有傳入這個參數。然後調用handleMessage方法處理。這個方法預設是空實現:    /**     * Subclasses must implement this to receive messages.     */    public void handleMessage(Message msg) {    }注釋已經說的很清楚,所以,你要處理訊息,必須重寫這個方法總的來說:對於主線程的話,就是首先放訊息到訊息佇列。然後主線程的looper迴圈檢查訊息佇列的訊息,因為looper對應線程。handler對應looper。然後looper把訊息給主線程的handler處理,實現獲得返回的狀態。如果不是主線程,系統沒有為新開的線程預設開啟looper和訊息機制。所以,必須你自己去處理在新線程中調用 Looper.prepare()方法構造looper對象     /** Initialize the current thread as a looper.      * This gives you a chance to create handlers that then reference      * this looper, before actually starting the loop. Be sure to call      * {@link #loop()} after calling this method, and end it by calling      * {@link #quit()}.      */    public static void prepare() {        if (sThreadLocal.get() != null) {            throw new RuntimeException("Only one Looper may be created per thread");        }//看到這句話了嗎?意思是為當前線程上綁定一個Looper對象。ThreadLocal是為了線程間共用變數用的//當下面調用Loooper.prepare後,就會為當前的線程建立一個唯一且只屬於當前線程的looper sThreadLocal.set(new Looper()); }然後主動啟動原來Activitythread.java--main()方法裡做的操作,調用loop()方法等待訊息:eg:class TestLooper extends Thread(){ public Handler mHandler; public void run(){ Looper.prepare() //下面執行個體化handler並處理訊息 ............ ............ Looper.loop() }} 下次,分析下handler內部封裝機制,其實,雖然我沒看,但是也能猜到,就是java中的那些線程啊,資料結構之類的結合,基礎,多麼的重要。累了,休息.......... 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.