組件之BroadcastReceiver源碼解析

一、BroadcastReceiver源碼解析

(1)BroadcastReceiver注冊過程

  • 注冊過程是從ContextWraper的registerReceiver方法開始的
    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
        //ContextWrapper是mBase的代理,mBase成員變量其實是ContextImpl。
        return mBase.registerReceiver(receiver, filter);
    }

    //ContextImpl.java
    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
        return registerReceiver(receiver, filter, null, null);
    }

    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
            String broadcastPermission, Handler scheduler) {
        return registerReceiverInternal(receiver, getUserId(),
                filter, broadcastPermission, scheduler, getOuterContext(), 0);
    }

    private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
            IntentFilter filter, String broadcastPermission,
            Handler scheduler, Context context, int flags) {
        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 {
            //注釋三
            final Intent intent = ActivityManager.getService().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
                    broadcastPermission, userId, flags);
            if (intent != null) {
                intent.setExtrasClassLoader(getClassLoader());
                intent.prepareToEnterProcess();
            }
            return intent;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
  • 注釋一:將廣播接收者及其他參數封裝成一個IIntentReceiver對象
  • 注釋二:最終返回的是IIntentReceiver.Stub類型的對象InnerReceiver,該類實現了IIntentReceiver接口并繼承Binder。
  • 注釋三:基于Binder機制,通過調用代理對象IActivityManager的方法,使得系統服務ActivityManagerService對應的方法被調用。因此,注冊的操作就交給了系統服務ActivityManagerService來處理了。
  • 查看LoadedApk.ReceiverDispatcher源碼
        ReceiverDispatcher(BroadcastReceiver receiver, Context context,
                Handler activityThread, Instrumentation instrumentation,
                boolean registered) {
            if (activityThread == null) {
                throw new NullPointerException("Handler must not be null");
            }
            //初始化IIntentReceiver類,InnerReceiver是IIntentReceiver實現類
            mIIntentReceiver = new InnerReceiver(this, !registered);
            mReceiver = receiver;
            mContext = context;
            mActivityThread = activityThread;
            mInstrumentation = instrumentation;
            mRegistered = registered;
            mLocation = new IntentReceiverLeaked(null);
            mLocation.fillInStackTrace();
        }
  • 查看ActivityManagerService.registerReceiver源碼
    public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
            int flags) {
        //code..
        synchronized (this) {
            //code...
            //注釋一
            ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
            if (rl == null) {
                rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                        userId, receiver);
                if (rl.app != null) {
                    final int totalReceiversForApp = rl.app.receivers.size();
                    //code...
                    rl.app.receivers.add(rl);
                } else {
                    try {
                        receiver.asBinder().linkToDeath(rl, 0);
                    } catch (RemoteException e) {
                        return sticky;
                    }
                    rl.linkedToDeath = true;
                }
                //注釋二
                mRegisteredReceivers.put(receiver.asBinder(), rl);
            } else if (rl.uid != callingUid) {
                //code...(IllegalArgumentException異常)
            } else if (rl.pid != callingPid) {
                throw new IllegalArgumentException(
                //code...(IllegalArgumentException異常)
            } else if (rl.userId != userId) {   
                //code...(IllegalArgumentException異常)
            }
            //注釋三
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId, instantApp, visibleToInstantApps);
            if (rl.containsFilter(filter)) {
                //code...
            } else {
                rl.add(bf);
                //注釋四
                mReceiverResolver.addFilter(bf);
            }
            //code...
            return sticky;
        }
    }
  • 注釋一:每次發來的一個注冊請求都會對應ReceiverList中的一條數據。
  • 注釋二:將客戶端傳遞過來的廣播接收器InnerReceiver保存起來。
  • 注釋三:創建一個BroadcastFilter對象,BroadcastFilter繼承自IntentFilter。
  • 注釋四:將客戶端傳遞過來的IntentFilter也保存起來,這樣整個廣播注冊過程就完成了。

總結

  • 客戶端:客戶端廣播注冊的時候,loadedApk對應著多個context對象(一個進程對應多個activity和service以及一個application),每個context里面有一張hashmap存放注冊的廣播接收者(每個activity里面可以注冊多個廣播,都存放在hashmap里),每張hashmap里面包含許多ReceiverDispatcher(內含binder);
  • AMS:每個客戶端的ReceiverDispatcher都對應一個ReceiverList,該ReceiverList中保存著可以啟動該廣播接收者的IntentFilter列表。而每一個ReceiverList都對應著接收者注冊時候的一個Binder對象。

(2)廣播的發送與接收

  • 廣播發送是從ContextWraper的sendBroadcast方法開始的
    @Override
    public void sendBroadcast(Intent intent) {
        mBase.sendBroadcast(intent);
    }

    //ContextImpl.java
    @Override
    public void sendBroadcast(Intent intent) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.prepareToLeaveProcess(this);
            ActivityManager.getService().broadcastIntent(
                    mMainThread.getApplicationThread(), intent, resolvedType, null,
                    Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                    getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
  • 查看ActivityManagerService.broadcastIntent源碼
    public final int broadcastIntent(IApplicationThread caller,
            Intent intent, String resolvedType, IIntentReceiver resultTo,
            int resultCode, String resultData, Bundle resultExtras,
            String[] requiredPermissions, int appOp, Bundle bOptions,
            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, resultExtras,
                    requiredPermissions, appOp, bOptions, serialized, sticky,
                    callingPid, callingUid, userId);
            Binder.restoreCallingIdentity(origId);
            return res;
        }
    }
  • 注釋一:獲取廣播發送者的身份
  • 注釋二:調用broadcastIntentLocked發送廣播
  • broadcastIntentLocked方法主要用來查找目標廣播接收者
    @GuardedBy("this")
    final int broadcastIntentLocked(ProcessRecord callerApp,
            String callerPackage, Intent intent, String resolvedType,
            IIntentReceiver resultTo, int resultCode, String resultData,
            Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
            boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
        intent = new Intent(intent);
        //code...
        //粘性廣播
        if (sticky) {
           //code...
        }
        //code...
        int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
        if (!ordered && NR > 0) {
            if (isCallerSystem) {
                checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
                        isProtectedBroadcast, registeredReceivers);
            }
            //通過傳遞過來的Intent查找相匹配的的BroadcastReceiver并把它放入到廣播隊列BroadcastQueue中。
            final BroadcastQueue queue = broadcastQueueForIntent(intent);
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
                    requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
                    resultCode, resultData, resultExtras, ordered, sticky, false, userId);
            final boolean replaced = replacePending
                    && (queue.replaceParallelBroadcastLocked(r) != null);
            if (!replaced) {
                queue.enqueueParallelBroadcastLocked(r);
                //執行廣播發送任務
                queue.scheduleBroadcastsLocked();
            }
            registeredReceivers = null;
            NR = 0;
        }
        //code...
        return ActivityManager.BROADCAST_SUCCESS;
    }
  • 查看BroadcastQueue.scheduleBroadcastsLocked源碼
    public void scheduleBroadcastsLocked() {
        if (mBroadcastsScheduled) {
            return;
        }
        //向消息管理器mHandler發送了一個BROADCAST_INTENT_MSG類型的消息
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    }
  • handleMessage中調用processNextBroadcast(true)方法,processNextBroadcast()方法又調用processNextBroadcastLocked(fromMsg, false)方法。
    final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
        BroadcastRecord r;
        mService.updateCpuStats();
        //fromMsg表示是否為BROADCAST_INTENT_MSG類型的消息
        if (fromMsg) {
            mBroadcastsScheduled = false;
        }
        //處理mParallelBroadcasts中的廣播轉發任務
        while (mParallelBroadcasts.size() > 0) {
            r = mParallelBroadcasts.remove(0);
            r.dispatchTime = SystemClock.uptimeMillis();
            r.dispatchClockTime = System.currentTimeMillis();
            if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
                Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                    createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),
                    System.identityHashCode(r));
                Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                    createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),
                    System.identityHashCode(r));
            }
            final int N = r.receivers.size();
            for (int i=0; i<N; i++) {
                Object target = r.receivers.get(i);
                //注釋一
                deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
            }
            addBroadcastToHistoryLocked(r);
        }
        //code...
    }
  • 注釋一:deliverToRegisteredReceiverLocked方法系統在檢查廣播發送者和接收者的權限之后,調用performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver, new Intent(r.intent), r.resultCode, r.resultData, r.resultExtras, r.ordered, r.initialSticky, r.userId);方法將BroadcastRecord對象r描述的廣播交給BroadcastFilter處理。
    void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
            Intent intent, int resultCode, String data, Bundle extras,
            boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
        if (app != null) {
            if (app.thread != null) {
                try {
                    //注釋一
                    app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                            data, extras, ordered, sticky, sendingUser, app.repProcState);
                } catch (RemoteException ex) {
                    synchronized (mService) {
                        app.scheduleCrash("can't deliver broadcast");
                    }
                    throw ex;
                }
            } else {
                throw new RemoteException("app.thread must not be null");
            }
        } else {
            receiver.performReceive(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
        }
    }
  • 注釋一:app.thread對象是ActivityThread的內部類對象ApplicationThread。
  • 查看ApplicationThread對象的scheduleRegisteredReceiver方法。
        public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
                int resultCode, String dataStr, Bundle extras, boolean ordered,
                boolean sticky, int sendingUser, int processState) throws RemoteException {
            updateProcessState(processState, false);
            //receiver指向一個InnerReceiver對象,每個InnerReceiver對象封裝了一個廣播接收者
            receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                    sticky, sendingUser);
        }
  • 查看InnerReceiver中的performReceive方法
            @Override
            public void performReceive(Intent intent, int resultCode, String data,
                    Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
                final LoadedApk.ReceiverDispatcher rd;
                if (intent == null) {
                    rd = null;
                } else {
                    rd = mDispatcher.get();
                }
                if (ActivityThread.DEBUG_BROADCAST) {
                    int seq = intent.getIntExtra("seq", -1);
                }
                if (rd != null) {
                    //rd是ReceiverDispatcher的對象,調用rd的performReceive
                    rd.performReceive(intent, resultCode, data, extras,
                            ordered, sticky, sendingUser);
                } else {
                    IActivityManager mgr = ActivityManager.getService();
                    try {
                        if (extras != null) {
                            extras.setAllowFds(false);
                        }
                        mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
                    } catch (RemoteException e) {
                        throw e.rethrowFromSystemServer();
                    }
                }
            }
  • 查看ReceiverDispatcher中的performReceive方法
        public void performReceive(Intent intent, int resultCode, String data,
                Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
            final Args args = new Args(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
            //code...
            //注釋一
            if (intent == null || !mActivityThread.post(args.getRunnable())) {
                if (mRegistered && ordered) {
                    IActivityManager mgr = ActivityManager.getService();
                    args.sendFinished(mgr);
                }
            }
        }
  • mActivityThread是一個Handler對象,該對象指向ActivityThread中的mH;因此此刻切換到廣播接收者所在進程的主線程來執行args,args是一個Runnable對象。
            public final Runnable getRunnable() {
                return () -> {
                    //code...
                    try {
                        ClassLoader cl = mReceiver.getClass().getClassLoader();
                        intent.setExtrasClassLoader(cl);
                        intent.prepareToEnterProcess();
                        setExtrasClassLoader(cl);
                        receiver.setPendingResult(this);
                        //廣播接收器BroadcastReceiver的onReceive方法被回調
                        receiver.onReceive(mContext, intent);
                    } catch (Exception e) {
                       //code...
                    }
                    //code...
                };
            }
        }

總結

發送廣播會查找相應的BroadcastFilter,匹配就會調用相應的遠程Binder代理對象通知客戶端,最終由客戶端的主線程來執行接受者的onReceiver()方法。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容