[學習筆記]Android開發藝術探索:四大組件的工作過程之BoradcastReceiver

廣播的註冊過程

靜態註冊:在應用的安裝時由系統自動完成註冊,具體來說是PMS(PackageManagerServer)來完成整個註冊過程。其他三大組件也是。

動態註冊:從ContentWrapper的registerReceiver方法開始, 調用了自己的registerReceiverInternal方法。

		private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
            IntentFilter filter, String broadcastPermission,
            Handler scheduler, Context context) {
        IIntentReceiver rd = null;
        if (receiver != null) {
            if (mPackageInfo != null && context != null) {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = mPackageInfo.getReceiverDispatcher(
                    receiver, context, scheduler,
                    mMainThread.getInstrumentation(), true);
            } else {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = new LoadedApk.ReceiverDispatcher(
                        receiver, context, scheduler, null, true).getIIntentReceiver();
            }
        }
        try {
            return ActivityManagerNative.getDefault().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName,
                    rd, filter, broadcastPermission, userId);
        } catch (RemoteException e) {
            return null;
        }
    } 

系統首先從mPackageInfo獲取IIntentReceiver對象,然後採用跨進程的方式向AMS發送廣播註冊的請求。所以採用IIntentReceiver而不是直接採用BroadCastReceiver是因爲這個過程是一個進程間通信的過程,他BroadCastReceiver是一個Android的組件是不能跨進程的,所以需要IIntentReceiver來中轉一下,毫無疑問,IIntentReceiver必然是一個Binder接口,他的具體實現是LoadedApk.ReceiverDispatcher.IIntentReceiver,ReceiverDispatcher內部同時保存了BoradcastReceiver和IIntentReceiver。

ReceiverDispatcher的getIIntentReceiver的實現:

		public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
            Context context, Handler handler,
            Instrumentation instrumentation, boolean registered) {
        synchronized (mReceivers) {
            LoadedApk.ReceiverDispatcher rd = null;
            ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
            if (registered) {
                map = mReceivers.get(context);
                if (map != null) {
                    rd = map.get(r);
                }
            }
            if (rd == null) {
                rd = new ReceiverDispatcher(r, context, handler,
                        instrumentation, registered);
                if (registered) {
                    if (map == null) {
                        map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
                        mReceivers.put(context, map);
                    }
                    map.put(r, rd);
                }
            } else {
                rd.validate(context, handler);
            }
            rd.mForgotten = false;
            return rd.getIIntentReceiver();
        }
    } 

getReceiverDispatcher方法重新創建了一個ReceiverDispatcher對象並將球保持的InnerReceiver對象返回,其中InnerReceiver對象和BroadcastReceiver都是在ReceiverDispatcher的構造方法中被保存起來的。

註冊廣播的真正實現是在AMS,AMS的registerReceiver方法:

		public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
          	
  					...					
  
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId);
            rl.add(bf);
            if (!bf.debugCheck()) {
                Slog.w(TAG, "==> For Dynamic broadast");
            }
            mReceiverResolver.addFilter(bf);

            ...
        }
    }

廣播的發送和接收過程

當send發送之後,AMS會查找出匹配的廣播接收器並且將廣播交給他去處理,關閉的發送有幾種:普通廣播,有序廣播 和 粘性廣播,他們的實現方式有一些不一樣,但是過程都是一樣的。

廣播的發送和接收,可以說是兩個階段。這裏從發射的廣播說起,廣播的發送仍然開始於ContextWrapper的sendBroadcast,之所以不是Context,那是因爲Context的sendBroadcast是一個抽象的方法,和廣播的註冊過程一樣,他也什麼都沒有做,也是ContextImpl去處理的。

 	@Override
   public void sendBroadcast(Intent intent) {
       warnIfCallingFromSystemProcess();
       String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
       try {
           intent.prepareToLeaveProcess();
           ActivityManagerNative.getDefault().broadcastIntent(
               mMainThread.getApplicationThread(), intent, resolvedType, null,
               Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, false,
               getUserId());
       } catch (RemoteException e) {
       }
   }

這段代碼裏,直接異步向AMS發送一個broadcastIntent

		public final int broadcastIntent(IApplicationThread caller,
            Intent intent, String resolvedType, IIntentReceiver resultTo,
            int resultCode, String resultData, Bundle map,
            String requiredPermission, int appOp, boolean serialized, boolean sticky, int userId) {
        enforceNotIsolatedCaller("broadcastIntent");
        synchronized(this) {
            intent = verifyBroadcastLocked(intent);

            final ProcessRecord callerApp = getRecordForAppLocked(caller);
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            int res = broadcastIntentLocked(callerApp,
                    callerApp != null ? callerApp.info.packageName : null,
                    intent, resolvedType, resultTo,
                    resultCode, resultData, map, requiredPermission, appOp, serialized, sticky,
                    callingPid, callingUid, userId);
            Binder.restoreCallingIdentity(origId);
            return res;
        }
    }

這裏隨即又調用了一個broadcastIntentLocked,這個方法就有點複雜了。在這個方法裏最開始有這麼一行

 		// By default broadcasts do not go to stopped apps.
   intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);

在Android5.0中,默認情況下廣播不會發送給已經停止的應用,其實在3.1就已經有這種特性,在broadcastIntentLocked內部,會根據intent-filter來匹配並且進行廣播過濾,最終將滿足的廣播添加到BrocastQueue中,接着就發送給對應的廣播接收者了。源碼如下:

 				int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
        if (!ordered && NR > 0) {
            // If we are not serializing this broadcast, then send the
            // registered receivers separately so they don't wait for the
            // components to be launched.
            final BroadcastQueue queue = broadcastQueueForIntent(intent);
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, resolvedType, requiredPermission,
                    appOp, registeredReceivers, resultTo, resultCode, resultData, map,
                    ordered, sticky, false, userId);
            if (DEBUG_BROADCAST) Slog.v(
                    TAG, "Enqueueing parallel broadcast " + r);
            final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
            if (!replaced) {
                queue.enqueueParallelBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();
            }
            registeredReceivers = null;
            NR = 0;
        }

下面我們看一下BroadcastQueue中廣播的發送過程

 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;
    }

就是發了一個Handler

  					// 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);
            }

在這段代碼中,會創建一個Args對象並且通過post方式執行Args的邏輯,而Args實現了Runnable的接口,在這裏面有這麼一段代碼

		final BroadcastReceiver receiver = mReceiver;
    receiver.setPendingResult(this);
    receiver.onReceiver(mContext,intent);

這個時候onReceiver被執行了,應用也就收到了廣播了,這就是整個廣播的工作過程。

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