Android 源码分析 启动广播的发送和接收过程

Posted 小图包

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 源码分析 启动广播的发送和接收过程相关的知识,希望对你有一定的参考价值。

广播的发送和接收过程

广播的发送和接收分为 2 个阶段来分析,通过应用进程到 AMS SystemServer 进程的调用,然后 AMS 所在的进程通知应用进程的调用,下面我们先来分析应用程序进程到 AMS

ContextImpl 到 AMS 的调用过程

广播发送多种类型的广播,比如 无序、有序、粘性广播,这里以最简单的广播无序广播来讲解,也就是发送一个普通广播,它的实现也是在 ContextWrapper 中

直接来看 ContextWrapper 的 sendBroadcast 方法,代码如下:

//ContextWrapper.java
    @Override
    public void sendBroadcast(Intent intent) 
      	//调用 Context 的实现类 ContextImpl
        mBase.sendBroadcast(intent);
    

这里的 mBase 是 Context , 在之前文章中将到了 ContextImpl 是 Context 的实现类,我们直接看它的实现,代码如下:

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

AMS 的代理类 IActivityManager 的 broadcastIntent 函数,我们发现跟咱么之前讲解的 Activity,Service 调用方式一样都会经过 AMS 的代理类 IActivityManager 

//AMS.java

    /**
     * 应用程序进程调用
     * @param caller
     * @param intent
     * @param resolvedType
     * @param resultTo
     * @param resultCode
     * @param resultData
     * @param resultExtras
     * @param requiredPermissions
     * @param appOp
     * @param bOptions
     * @param serialized
     * @param sticky
     * @param userId
     * @return
     */
    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) 
            /**
             * 1. 验证广播是否合法
             */
            intent = verifyBroadcastLocked(intent);
            /**
             * 拿到所在的进程
             */
            final ProcessRecord callerApp = getRecordForAppLocked(caller);
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            /**
             * 2. 
             */
            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;
        
    

我们先看注释 1 内部验证广播代码实现:

//AMS.java

    final Intent verifyBroadcastLocked(Intent intent) 
        // Refuse possible leaked file descriptors
        /**
         * 1. 验证 intent 是否不为null 并且有文件描述符
         */
        if (intent != null && intent.hasFileDescriptors() == true) 
          ...
          

        /**
         * 2. 获得 intent 的 flags
         */
        int flags = intent.getFlags();

        if (!mProcessesReady) 
            /**
             * 3. 系统正在启动过程中。如果是动态广播者不做处理
             */
            if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) 
                
                /**
                 * 4. 如果 flag 没有设置为 FLAG_RECEIVER_REGISTERED_ONLY 只接受动态注册的广播接收者则会抛出异常
                 */
             else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) 
            ...    
            
        

				...

        return intent;
    

根据上面的注释我们知道就是对 Intent 判断是否合法性,下面我们继续回到 broadcastIntent 注释 2 ,代码如下:

//AMS.java
    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) 
      ...
        
            /**
             * 1. 创建 BroadcastRecord 对象将 receivers 传进去。
             */
            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);
                /**
                 * 2.
                 */
                //处理广播分发
                queue.scheduleBroadcastsLocked();
            
            registeredReceivers = null;
            NR = 0;
        
        
      ...
      
         

注释 1 上面省略了很多代码,省略的代码如要是把注册 动态/静态的广播接收者按照优先级高低不同储存在不同的列表中,在将这 2 个列表合并到 receivers 列表中,这样 receivers 列表包含了所有的广播接收者。在注释 1 处创建 BroadcastReceiver 对象并将 receivers 传递进去,在注释 2 处调用 BroadcastQuque 的 scheduleBroadcastsLocked 方法。

AMS 到 BroadcastReceiver 的调用过程

AMS 到 BroadcastReceiver 的调用过程请直接看 BroadcastQueue 的 scheduleBroadcastsLocked 函数实现,代码如下:

//BroadcastQueue.java

    public void scheduleBroadcastsLocked() 
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
                + mQueueName + "]: current="
                + mBroadcastsScheduled);

        if (mBroadcastsScheduled) 
            return;
        
        //通过 Handler 分发
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    

上面的代码向 BroadcastHandler 类型的 mHandler 对象发送了 BROADCAST_INTENT_MSG 类型的消息,这个消息在 BroadcastHandler 的 handleMessage 方法中进行处理,如下所示:

    //BroadcastQueue.java
 		private final class BroadcastHandler extends Handler 
        public BroadcastHandler(Looper looper) 
            super(looper, null, true);
        

        @Override
        public void handleMessage(Message msg) 
            switch (msg.what) 
                case BROADCAST_INTENT_MSG: 
                    if (DEBUG_BROADCAST) Slog.v(
                            TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");
                    //处理下一个广播
                    processNextBroadcast(true);
                 break;
                case BROADCAST_TIMEOUT_MSG: 
                    synchronized (mService) 
                        broadcastTimeoutLocked(true);
                    
                 break;
            
        
    

面的代码向 BroadcastHandler 类型的 mHandler 对象发送了 BROADCAST_INTENT_MSG 类型的消息,这个消息在 BroadcastHandler 的 handleMessage 方法中进行处理,如下所示

    //BroadcastQueue.java
 		private final class BroadcastHandler extends Handler 
        public BroadcastHandler(Looper looper) 
            super(looper, null, true);
        

        @Override
        public void handleMessage(Message msg) 
            switch (msg.what) 
                case BROADCAST_INTENT_MSG: 
                    if (DEBUG_BROADCAST) Slog.v(
                            TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");
                    //处理下一个广播
                    processNextBroadcast(true);
                 break;
                case BROADCAST_TIMEOUT_MSG: 
                    synchronized (mService) 
                        broadcastTimeoutLocked(true);
                    
                 break;
            
        
    

在 handleMessage 方法中调用了 processnextBroadcast 方法,方法对无序广播和有序广播分别进行处理,在将广播发送给广播接收者,处理代码如下:

//BroadcastQueue.java

    final void processNextBroadcast(boolean fromMsg) 
        synchronized(mService) 
            BroadcastRecord r;

  				...
            mService.updateCpuStats();

            if (fromMsg) 
                /**
                 * 1.  已经处理了  BROADCAST_INTENT_MSG 这条消息
                 */
            
                mBroadcastsScheduled = false;
            

            /**
             * 2. 遍历存储无序广播的 mParallelBroadcasts 列表
             */
            while (mParallelBroadcasts.size() > 0) 
                /*** 3.获取无序广播 */
                r = mParallelBroadcasts.remove(0);
                ...
                
                for (int i=0; i<N; i++) 
                    Object target = r.receivers.get(i);
                 /**
                 * 4. 将 r 对象描述的广播发送给对应的广播者
                 */
                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
                

                addBroadcastToHistoryLocked(r);
                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
                        + mQueueName + "] " + r);
            

            ...
        
    

从前面 BroadcastHandler 方法中我们得知传入的参数 fromMsg 的值为 true,因此在注释1 处将 mBroadcastsScheduled 设置为 flase, 表示对于此前发来的 BROADCAST_INTENT_MSG 类型的消息已经处理了。在注释 2 处的 mParallelBroadcasts 列表用来存储无序广播,通过 while 循环将 mParallelBroadcasts 列表中的无序广播发送给对应的广播接收者。在注释 3 处获取每一个 mParallelBroadcasts 列表中存储的 BroadcastRecord 类型的 r 对象。在注释 4 处将这些 r 对象描述的广播发送给对应的广播接收者,deliverToRegisteredReceiverLocked 方法,如下所示:

//BroadcastQueue.java


    private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
            BroadcastFilter filter, boolean ordered, int index) 
     ...
       
                 if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) 
                 if (ordered) 
                    skipReceiverLocked(r);
                
             else 
                /***
                 * 1.
                 */
                performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                        new Intent(r.intent), r.resultCode, r.resultData,
                        r.resultExtras, r.ordered, r.initialSticky, r.userId);
              
       
     ...
       
      
    


deliverToRegisteredReceiverLocked 内部代码如要是用来检查广播发送者和广播接收者的权限,如果通过了权限的检查,则会调用注释 1 处的 performReceiveLocked 方法。

//BroadcastQueue.java

    void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
            Intent intent, int resultCode, String data, Bundle extras,
            boolean ordered, boolean sticky, int sendingUser) throws RemoteException 
        /**
         * 1. 
         */
        if (app != null) 
            /**
             * 2. 
             */
            if (app.thread != null) 
                
                try 
                    /**
                     * 3. 
                     */
                    app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                            data, extras, ordered, sticky, sendingUser, app.repProcState);
                ...
    

在注释 1 处和注释 2 处的代码表示如果广播的接收者所在的应用程序进程存在并且正在运行,则执行注释 3 处的代码,表示用广播接收者所在的应用程序进程来接收广播,这里 app.thread 指的是 ApplicationThread,它其实在 ActivityThread 内部类中,继承于 IApplicationThread.Stub 下面我们看它的实现,代码如下:


 

//ActivityThread.java

    private class ApplicationThread extends IApplicationThread.Stub 
    ...
      
            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);
      			/***1. 调用 IIntentReceiver 中的 performReceive 函数*/
            receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                    sticky, sendingUser);
        
    ...
      
    

在注释 1 中调用了 IIntentReceiver 的 performReceive 函数,IItentReceiver 在前面提到过,用于广播的跨进程的通信,它的具体实现在 LoadedApk.ReceiverDispatcher.InnerReceiver,代码如下:


 

//LoadedApk.java
    static final class ReceiverDispatcher 

        final static class InnerReceiver extends IIntentReceiver.Stub 
            final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
            final LoadedApk.ReceiverDispatcher mStrongRef;

            InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) 
                mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
                mStrongRef = strong ? rd : null;
            

            @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) 
                    Log.wtf(TAG, "Null intent received");
                    rd = null;
                 else 
                    rd = mDispatcher.get();
                
              ...
                if (rd != null) 
                  //1. 
                    rd.performReceive(intent, resultCode, data, extras,
                            ordered, sticky, sendingUser);
                 else 
                   ...
                
            
        
      ....
        
    

其实 IIntentReceiver 和 IActivityManager 一样,都使用了 aidl 来实现进程间通信。InnerReceiver 继承自 IIntentReceiver.Stub,是 Binder 通信的服务器端, IIntentReceiver 则是 Binder 通信的客服端、InnerReceiver 在本地的代理,它的具体的实现就是 InnerReceiver. 在 InnerReceiver 的 performReceiver 方法的注释 1 调用了 ReceiverDispatch 类型的 rd 对象的 performReceive 方法,代码如下:

//LoadedApk.java
        public void performReceive(Intent intent, int resultCode, String data,
                Bundle extras, boolean ordered, boolean sticky, int sendingUser) 
            /**
             * 1. 
             */
            final Args args = new Args(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
           ...
            /**
             * 2. 
             */
            if (intent == null || !mActivityThread.post(args.getRunnable())) 
                if (mRegistered && ordered) 
                    IActivityManager mgr = ActivityManager.getService();
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing sync broadcast to " + mReceiver);
                    args.sendFinished(mgr);
                
            
        

    

在注释 1 处将广播的 intent 等信息封装到了为 Args 对象中,在注释 2 处调用 mActivityThread 的 post 方法并传入了 Args 对象。在这个 mActivityThread 是一个 Handler 对象,具体指向的就是 H 类,在注释 2 处的代码就是将 Args 对象的 getRunnable 方法通过 H 发送到线程的消息队列中, Args 中的实现,代码如下:


 

//LoadedApk.java

        final class Args extends BroadcastReceiver.PendingResult 
            private Intent mCurIntent;
            private final boolean mOrdered;
            private boolean mDispatched;
            private Throwable mPreviousRunStacktrace; // To investigate b/37809561. STOPSHIP remove.

            public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
                    boolean ordered, boolean sticky, int sendingUser) 
                super(resultCode, resultData, resultExtras,
                        mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
                        sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
                mCurIntent = intent;
                mOrdered = ordered;
            

            public final Runnable getRunnable() 
                return () -> 
                    final BroadcastReceiver receiver = mReceiver;
                    ...
                    try 
                        ClassLoader cl = mReceiver.getClass().getClassLoader();
                        intent.setExtrasClassLoader(cl);
                        intent.prepareToEnterProcess();
                        setExtrasClassLoader(cl);
                        receiver.setPendingResult(this);
                        //1. 回调到接收广播的 onReceiver
                        receiver.onReceive(mContext, intent);
                     catch (Exception e) 
                        ...
                  
                ;
            
        

在注释 1 处执行了 BroadcastReceiver 回调 **onReceive(mContext, intent);**方法,这样注册广播接收者就收到了广播并得到了 intent ,整个流程到这里就讲解完了

以上是关于Android 源码分析 启动广播的发送和接收过程的主要内容,如果未能解决你的问题,请参考以下文章

BroadcastReceiver源码分析

BroadcastReceiver源码分析

Android 7.0 ActivityManagerService 广播(Broadcast)相关流程分析

说说Android的广播(1)

android 广播自定义广播接收问题

Android广播阻塞、延迟问题