Android BroadcastReceiver的工作流程源码分析(8.0)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pihailailou/article/details/78640128

一,写在前面

       本篇文章会从源码角度分析广播的工作流程,具体来说是分为两部分:广播的注册,发送广播。在阅读本篇文章前,建议先了解Activity,Service相关的工作流程。本篇文章将不再分析工作流程中的重复细节,参考文章:

二,广播的注册,交给ContextImpl

        广播的注册分为静态注册,以及动态注册。静态注册是在xml中配置<receiver>节点,在应用程序启动后会解析xml文件,具体的注册流程是交给PackagerManagerService来处理。本篇文章主要分析广播的动态注册,也就是在Java代码中调用registerReceiver方法来注册广播,开发中具体的使用这里不再介绍。
       不管是在Activity,还是Service中注册广播,都是调用ContextWrapper$registerReceiver方法。其中,ContextWrapper是Context的一个子类,在抽象类Context中定义了抽象方法registerReceiver,具体实现在子类ContextWrapper中。
       查看ContextWrapper$registerReceiver源码:
@Override
    public Intent registerReceiver(
        BroadcastReceiver receiver, IntentFilter filter) {
        return mBase.registerReceiver(receiver, filter);
    }
       第4行,变量mBase是Context类型,而Context是一个抽象类,其实mBase的具体实现类是ContextImpl。至于具体原因,可以查看文章  Android Activity的启动流程源码解析(8.0) ,这里不再重复阐述。

       查看ContextImpl相关源码:
    @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();
            }
        }
        
	//...code

            final Intent intent = ActivityManager.getService().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
                    broadcastPermission, userId, flags);           
          
        //...code
    }
       第17行,ContextImpl$registerReceiver有多个重载方法,但最终都会调用ContextImpl$registerReceiverInternal方法。
       第24行,mMainThread是一个ActivityThread类型的变量,它的实例化在ContextImpl的构造方法中。mMainThread.getHandler()返回一个H类型的对象,H是ActivityThread的内部类,继承了Handler。值得一提的是,在启动Activity,Service的工作流程中,都会创建一个上下文环境,也就是会创建ContextImpl对象。具体分析,见文章  Android Activity的启动流程源码解析(8.0) ,这里不再重复阐述。
       
       第26行,变量mPackageInfo是一个LoadedApk的变量,这里是将BroadcastReceiver对象封装到ReceiverDispatcher中,并最终返回IIntentReceiver类型的对象。有意思的是,ReceiverDispatcher与绑定服务中的ServiceDispatcher比较类似,都是将组件对象进行封装,并返回一个Binder对象,用于实现组件对象在进程间的通信。      
       由于逻辑与绑定服务流程中的LoadedApk$ServiceDispacher类似,具体分析可参考文章  Android Service的绑定流程源码分析(8.0) 。这里rd返回IIntentReceiver类型的对象,它的具体实现类是LoadedApk$ReceiverDispatcher$InnerReceiver,其具体结构:final static class InnerReceiver extends IIntentReceiver.Stub 。
       第33行,当mPackageInfo为null时,给rd赋值,做的事情与前面讲到的第26行一样。

       第40行,ActivityManager.getService()返回一个IActivityManager的代理对象,调用其registerReceiver方法会向系统服务发送一个请求,基于Binder机制,会调用ActivityManagerService$ActivityManage方法。具体分析,见文章  Android Activity的启动流程源码解析(8.0) ,这里不再重复阐述。

三,广播的注册,交给ActivityManagerService处理

       查看ActivityManagerService$ActivityManage方法源码:
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
            int flags) {
    
    //...code
    
            if (callerApp != null && (callerApp.thread == null
                    || callerApp.thread.asBinder() != caller.asBinder())) {
                // Original caller already died
                return null;
            }
            ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
            if (rl == null) {
                rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                        userId, receiver);
                if (rl.app != null) {
                    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);
            }

     //...code

            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId, instantApp, visibleToInstantApps);
            rl.add(bf);
            if (!bf.debugCheck()) {
                Slog.w(TAG, "==> For Dynamic broadcast");
            }
            mReceiverResolver.addFilter(bf);

    //...code
	    	    	    
}
       第8行,caller是一个IApplicationThread类型的变量,是一个Binder对象,具体源码见文章  Android Activity的启动流程源码解析(8.0) ,这里会检查它的对应的Binder对象。
       
       第12行,变量mRegisteredReceivers的定义: HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>()。
       key:receiver.asBinder()返回的是IIntentReceiver对象对应的Binder对象。IIntentReceiver前面已经分析过了,它封装了BroadcastReceiver对象,且是一个Binder对象。    
       value:ReceiverList类型的对象,它是一个存储BroadcastFilter对象的List集合。结构:class ReceiverList extends ArrayList<BroadcastFilter> implements IBinder.DeathRecipient。

       第14行,创建ReceiverList对象,注意最后一个参数receiver,说明ReceiverList封装了InnerReceiver对象。
       第31行,BroadcastFilter结构:class BroadcastFilter extends IntentFilter 。BroadcastFilter对象中封装了ReceiverList对象,IntentFilter对象。
       第37行,mReceiverResolver是一个IntentResolver类型的变量,该类里面维护了集合,并调用addFilter方法将bf存储起来。
       
       也就是说,注册广播的就是将InnerReceiver对象,IntentFilter对象封装在类BroadcastFilter中,并最终将BroadcastFilter对象存储在变量mReceiverResolver中。值得一提的是,在发送广播的流程中,会取出变量mReceiverResolver中存储的广播接受者相关的数据。动态注册广播的分析,到此就结束了~

四,发送广播,交给ContextImpl处理

       与动态注册广播一样,发送广播实际上调用的ContextWrapper$sendBroadcast方法;
       查看ContextWrapper$sendBroadcast方法源码:
@Override
    public void sendBroadcast(Intent intent) {
        mBase.sendBroadcast(intent);
    }
       第3行,变量mBase实现类是ContextImpl,与动态注册广播一样的。
       
       查看ContextImpl$sendBroadcast方法源码:
public void sendBroadcast(Intent intent) {
    //...

    ActivityManager.getService().broadcastIntent(
                    mMainThread.getApplicationThread(), intent, resolvedType, null,
                    Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                    getUserId());
   
    //...		 
}
       ActivityManager.getService()返回一个IActivityManager接口的代理对象,向系统服务AMS发起一个请求,会调用ActivityManagerService$broadcastIntent方法。具体细节不再分析,动态注册广播时已经提到。

五,发送广播,交给ActivityManagerService处理

       查看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) {        
	//...

        synchronized(this) {
            intent = verifyBroadcastLocked(intent);
		
        //...

            int res = broadcastIntentLocked(callerApp,
                    callerApp != null ? callerApp.info.packageName : null,
                    intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                    requiredPermissions, appOp, bOptions, serialized, sticky,
                    callingPid, callingUid, userId);
        //...     
            return res;
        }
    }
       第9行,主要对intent的flag进行检查;
       第13行,查看ActivityManagerService$broadcastIntentLocked方法源码:
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) {
	
	    //...

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

	    //...

	    registeredReceivers = mReceiverResolver.queryIntent(intent,
                        resolvedType, false /*defaultOnly*/, userId);

            //...

	    BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
                    requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
                    resultCode, resultData, resultExtras, ordered, sticky, false, userId);

	    //...

	    queue.enqueueParallelBroadcastLocked(r);
            queue.scheduleBroadcastsLocked();
	    
	    //...

}
       第10行,设置flag为FLAG_EXCLUDE_STOPPED_PACKAGES时,广播不会发送给已经停止的应用。本篇文章是基于8.0的源码,其实从Android3.1开始,发送广播会默认添加flag为FLAG_EXCLUDE_STOPPED_PACKAGES,禁止向停止应用发送广播,为了避免调用已经停止的应用。另外,若想将广播发送给已经停止的应用,也可以设置flag为FLAG_INCLUDE_STOPPED_PACKAGES。值得一提的是,应用处于停止状态意思是:应用安装后没有启动,或被手动,其他应用强行停止了。

       第14行,前面分析广播注册流程,最后有提到变量mReceiverResolver,它存储了BroadcastFilter对象,也就是存放了广播接受者相关的信息。调用IntentResolver$queryIntent方法用于获取与该intent相匹配的广播接受者,返回的是一个List集合,因此变量registeredReceivers是一个List类型变量。

       第21行,将变量registeredReceivers封装在BroadcastRecord对象中。
       第26行,变量queue是一个BroadcastQueue类型的对象,BroadcastQueue queue = broadcastQueueForIntent(intent)。
       查看BroadcastQueue$enqueueParallelBroadcastLocked方法源码:
public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
        mParallelBroadcasts.add(r);
        enqueueBroadcastHelper(r);
    }
       第2行,变量mParallelBroadcasts是一个ArrayList类型的对象,用于存放BroadcastRecord对象。ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<>()。后面,会取出mParallelBroadcasts集合中的数据,完成广播的接受。

       继续回到ActivityManagerService$broadcastIntentLocked的第27行,调用了queue.scheduleBroadcastsLocked(),这个是重点入口。

六,广播的接收

       查看BroadcastQueue相关方法源码:
public void scheduleBroadcastsLocked() {
	//...code

	mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));

	//...code
}

//继续查看...

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;
                
		//...code

            }
        }
    }

//继续查看...

final void processNextBroadcast(boolean fromMsg) {
    synchronized(mService) {
         BroadcastRecord r;
	  
	 //...=
	    
	 if (fromMsg) {
                mBroadcastsScheduled = false;
         }   

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

                for (int i=0; i<N; i++) {
                    Object target = r.receivers.get(i);
                    
		    //...	

                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
                }
                
		//...

            }
       
            //...
	    	    
    }
}
       第4行,发送一个what为BROADCAST_INTENT_MSG的消息;
       第19行,处理what为BROADCAST_INTENT_MSG的消息;
       第22行,继续调用processNextBroadcast方法;

       第44行,变量mParallelBroadcasts前面已经讲过,是一个ArrayList集合,存储了BroadcastRecord对象,而BroadcastRecord对象封装了广播接受者相关的信息;
       第45行,取出index为0的BroadcastRecord对象,并将该对象删除;
       第51行,r.receivers返回一个List集合,里面存放了BroadcastFilter对象。注册广播流程中已经分析过BroadcastFilter对象,它封装了广播接受者相关的信息。
       第55行,对r.receivers对应的集合进行遍历,完成所有匹配的BroadcastReceiver对广播的接受。然后会调用deliverToRegisteredReceiverLocked方法,这个是一个重要入口。

       查看BroadcastQueue$deliverToRegisteredReceiverLocked方法源码:
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
            BroadcastFilter filter, boolean ordered, int index) {
	//...code

	performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                        new Intent(r.intent), r.resultCode, r.resultData,
                        r.resultExtras, r.ordered, r.initialSticky, r.userId);

	//...code

}

//继续查看...

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) {
                // If we have an app thread, do the call through that so it is
                // correctly ordered with other one-way calls.
                try {
                    app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                            data, extras, ordered, sticky, sendingUser, app.repProcState);
	    
		//...

	    }
	 
	    //...
	 }

	//...
}
       第21,22行,对app,app.thread进行判空检查;
       第26行,app.thread返回IApplicationThread接口的代理对象,最终会调用ApplicationThread$scheduleRegisteredReceiver方法。关于ApplicationThread的描述,这里不能理解的,请参考文章  Android Activity的启动流程源码解析(8.0)  ,这里不再重复阐述。

       查看ActivityThread$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.performReceive(intent, resultCode, dataStr, extras, ordered,
                    sticky, sendingUser);
}
       第5行,变量receiver是一个IIntentReceiver类型的对象,在注册广播的流程中提到过IIntentReceiver,它的具体实现类是LoadedApk$ReceiverDispatcher$InnerReceiver。其实InnerReceiver是一个Binder接口,封装BroadcastReceiver对象后,使组件对象可以在进程间传递。
       
       查看LoadedApk$ReceiverDispatcher$InnerReceiver$performReceive方法源码:
    @Override
    public void performReceive(Intent intent, int resultCode, String data,
	    Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
	//...
		
	final LoadedApk.ReceiverDispatcher rd;

	//...

	rd.performReceive(intent, resultCode, data, extras,
                            ordered, sticky, sendingUser);

	//...		    		    
    }
       第10行,调用LoadedApk$ReceiverDispatcher$performReceive方法;

       查看LoadedApk$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);

	//...

	if (intent == null || !mActivityThread.post(args.getRunnable())) {
		
		//...
	
	}
}
       第10行,变量mActivityThread是ActivityThread$H类型的对象,它继承了Handler,接受广播的操作是在Handler所在的线程中执行,也就是在ActivityThread主线程中执行。
       args.getRunnable()返回一个Runnable接口;
       
       查看LoadedApk$ReceiverDispatcher$Args源码如下:
final class Args extends BroadcastReceiver.PendingResult {
    //...

    public final Runnable getRunnable() {
	return () -> {
	    final BroadcastReceiver receiver = mReceiver;
	    
	    //...
	    
	    receiver.onReceive(mContext, intent);
	    
	    //...
			       
	};
    }
}	
       第10行,回调BroadcastReceiver$onReceive方法,于是前面注册的广播接受者,就接收到发送的广播了~

七,最后

       本篇文章,从动态注册广播,发送广播,接收广播来分析BroadcastReceiver的工作机制。
       阅读本篇文章前,建议先阅读如下文章:













       

       






       
       
       

猜你喜欢

转载自blog.csdn.net/pihailailou/article/details/78640128
今日推荐