1. 程式人生 > >Android廣播機制實現原始碼淺析(二)

Android廣播機制實現原始碼淺析(二)

緊接著上篇的分析,我們現在來分析一下處理廣播的程式碼流程,也就是在方法queue.scheduleBroadcastsLocked();之後的操作
這些方法在BroadcastQueue.java中。在這裡能看到我們常說的廣播超時,以及我們重寫onReceive什麼時候執行。
public void scheduleBroadcastsLocked() {
        if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts ["
                + mQueueName + "]: current="
                + mBroadcastsScheduled);

        if (mBroadcastsScheduled) {
            return;
        }
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
}

final Handler mHandler = new Handler() {
        //public Handler() {
        //    if (localLOGV) Slog.v(TAG, "Handler started!");
        //}

        public void handleMessage(Message msg) {
            switch (msg.what) {
                case BROADCAST_INTENT_MSG: {
                    if (DEBUG_BROADCAST) Slog.v(
                            TAG, "Received BROADCAST_INTENT_MSG");
                    processNextBroadcast(true);
                } break;
                case BROADCAST_TIMEOUT_MSG: {
                    synchronized (mService) {
                        broadcastTimeoutLocked(true);
                    }
                } break;
            }
        }
};


可以看到這裡在分發廣播時直接post一個訊息到佇列中,不影響後面的此過程的後續操作,這說明發送和處理廣播是一個非同步操作,後面才是真正的處理過程。
final void processNextBroadcast(boolean fromMsg) {
……
// First, deliver any non-serialized broadcasts right away.
            while (mParallelBroadcasts.size() > 0) {
                r = mParallelBroadcasts.remove(0);
                r.dispatchTime = SystemClock.uptimeMillis();
                r.dispatchClockTime = System.currentTimeMillis();
                final int N = r.receivers.size();
                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast ["
                        + mQueueName + "] " + r);
                for (int i=0; i<N; i++) {
                    Object target = r.receivers.get(i);
                    if (DEBUG_BROADCAST)  Slog.v(TAG,
                            "Delivering non-ordered on [" + mQueueName + "] to registered "
                            + target + ": " + r);
                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
                }
                addBroadcastToHistoryLocked(r);
                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast ["
                        + mQueueName + "] " + r);
            }
……
}

這裡的先處理的是mParallelBroadcasts中的接收器,前文的分析中得知這個裡面的接收器全部都是無序廣播接收器中動態註冊的,而靜態註冊的以及有序廣播的都是在mOrderedBroadcasts中,本文先對無序動態的流程進行說明。
<pre name="code" class="html">private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,
            BroadcastFilter filter, boolean ordered) {
……
            try {
                if (DEBUG_BROADCAST_LIGHT) {
                    int seq = r.intent.getIntExtra("seq", -1);
                    Slog.i(TAG, "Delivering to " + filter
                            + " (seq=" + seq + "): " + r);
                }
                performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                    new Intent(r.intent), r.resultCode, r.resultData,
                    r.resultExtras, r.ordered, r.initialSticky, r.userId);
                if (ordered) {
                    r.state = BroadcastRecord.CALL_DONE_RECEIVE;
                }
            } catch (RemoteException e) {
                Slog.w(TAG, "Failure sending broadcast " + r.intent, e);
                if (ordered) {
                    r.receiver = null;
                    r.curFilter = null;
                    filter.receiverList.curBroadcast = null;
                    if (filter.receiverList.app != null) {
                        filter.receiverList.app.curReceiver = null;
                    }
                }
            }
}
private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
            Intent intent, int resultCode, String data, Bundle extras,
            boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
        // Send the intent to the receiver asynchronously using one-way binder calls.
        if (app != null && app.thread != null) {
            // If we have an app thread, do the call through that so it is
            // correctly ordered with other one-way calls.
            app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                    data, extras, ordered, sticky, sendingUser);
        } else {
            receiver.performReceive(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
        }
}



這裡的app.thread就是傳送廣播應用的ApplicationThreadProxy,這裡用到了跨程序通訊的知識,
簡要說一下,所有的應用程序在建立時就新建了一個activitythread和一個appliacationthread,前者用於處理主執行緒的使用者互動操作和介面重新整理操作。後者主要使用者和system service進行跨程序的呼叫。
ApplicationThread是ActivityThread的一個內部類,所以接下來看檔案ActivityThread.java中的
<pre name="code" class="html">public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
                int resultCode, String dataStr, Bundle extras, boolean ordered,
                boolean sticky, int sendingUser) throws RemoteException {
            receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                    sticky, sendingUser);
}

這裡的receiver就是在廣播註冊過程中關聯上的,它的實現是Loadedapk. ReceiverDispatcher. InnerReceiver,這個在動態註冊廣播時ContextImpl中的registerReceiverInternal方法中有體現,繼續往下:
static final class ReceiverDispatcher {
final static class InnerReceiver extends IIntentReceiver.Stub {
public void performReceive(Intent intent, int resultCode, String data,
                    Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
                 ……
If (rd != null) {
                    rd.performReceive(intent, resultCode, data, extras,
                            ordered, sticky, sendingUser);
                }
                ……..
}
}

        public void performReceive(Intent intent, int resultCode, String data,
                Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
            if (ActivityThread.DEBUG_BROADCAST) {
                int seq = intent.getIntExtra("seq", -1);
                Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq
                        + " to " + mReceiver);
            }
            Args args = new Args(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
            if (!mActivityThread.post(args)) {
                if (mRegistered && ordered) {
                    IActivityManager mgr = ActivityManagerNative.getDefault();
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing sync broadcast to " + mReceiver);
                    args.sendFinished(mgr);
                }
            }
        }

final class Args extends BroadcastReceiver.PendingResult implements Runnable {
public void run() {
               ………
try {
                    ClassLoader cl =  mReceiver.getClass().getClassLoader();
                    intent.setExtrasClassLoader(cl);
                    setExtrasClassLoader(cl);
                    receiver.setPendingResult(this);
                    receiver.onReceive(mContext, intent);
                } catch (Exception e) {
                    if (mRegistered && ordered) {
                        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                "Finishing failed broadcast to " + mReceiver);
                        sendFinished(mgr);
                    }
                    if (mInstrumentation == null ||
                            !mInstrumentation.onException(mReceiver, e)) {
                        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                        throw new RuntimeException(
                            "Error receiving broadcast " + intent
                            + " in " + mReceiver, e);
                    }
                }
                
                if (receiver.getPendingResult() != null) {
                    finish();
                }
……………
}
}
}



這裡mActivityThread成員變數的型別為Handler,它是前面動態註冊廣播接收器時,從ActivityThread取得的應用主執行緒的Handler,並把訊息post到訊息佇列中去,因此,ReceiverDispatcher不等這個廣播被應用處理就返回了,這裡也體現了廣播的傳送和處理是非同步進行的。 最終執行的是Args裡面的run方法,在這裡執行了註冊時儲存的BroadcastReceiver例項的onReceive方法。這樣就完成了一次廣播處理過程。

說到這裡我們分析了一個動態註冊廣播接收器處理非有序廣播的過程,也留下了兩個疑問,一個是靜態廣播以及有序廣播的處理過程,還有一個就是前面提到的廣播超時問題沒有說明,下篇將對這兩個問題進行繼續分析。