基于N源码的广播注册和发送流程分析
来源:互联网 发布:网络平台招商合同 编辑:程序博客网 时间:2024/05/18 01:50
广播可分为普通广播、有序广播和粘性广播,广播的注册方式分为静态注册和动态注册。在N上删除了三项隐式广播,以帮助优化内存使用和电量消耗。这三者广播为:CONNECTIVITY_ACTION;ACTION_NEW_PICTURE;ACTION_NEW_VIDEO。意思就是在AndroidManifest文件中静态注册是无法接受到通知,必须动态注册才可以。
下面看到动态注册的流程:
同样进入ContextImpl.java:
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()); }
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId, IntentFilter filter, String broadcastPermission, Handler scheduler, Context context) { IIntentReceiver rd = null; rd = new LoadedApk.ReceiverDispatcher( receiver, context, scheduler, null, true).getIIntentReceiver(); final Intent intent = ActivityManagerNative.getDefault().registerReceiver( mMainThread.getApplicationThread(), mBasePackageName, rd, filter, broadcastPermission, userId); }
这里创建了IIntentReceiver对象,进入LoadedApk.java跟踪下该对象的创建:
ReceiverDispatcher(BroadcastReceiver receiver, Context context, Handler activityThread, Instrumentation instrumentation, boolean registered) { if (activityThread == null) { throw new NullPointerException("Handler must not be null"); } mIIntentReceiver = new InnerReceiver(this, !registered); mReceiver = receiver; mContext = context; mActivityThread = activityThread; mInstrumentation = instrumentation; mRegistered = registered; mLocation = new IntentReceiverLeaked(null); mLocation.fillInStackTrace(); }
BroadcastReceiver getIntentReceiver() { return mReceiver; }
可以看到这个IIntentReceiver对象是IntentReceiver类型:
final static class InnerReceiver extends IIntentReceiver.Stub {
看到继承stub就明白它是服务端的真正实现者。这里先记下。
接着看下面:
final Intent intent = ActivityManagerNative.getDefault().registerReceiver( mMainThread.getApplicationThread(), mBasePackageName, rd, filter, broadcastPermission, userId);
这里的ActivityManagerNative.getDefault()是服务端的本地代理ActivityManagerProxy,调用registerReceiver会跨进程进入到服务的实现者AMS,并传递了两个binder对象:ApplicationThread和InnerReceiver,它们身处客户端却也是服务端的实现者。这里不明白的同学可以翻阅我前面几篇文章。
进入AMS的registerReceiver:
public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String permission, int userId) { ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder()); if (rl == null) { rl = new ReceiverList(this, callerApp, callingPid, callingUid, userId, receiver); mRegisteredReceivers.put(receiver.asBinder(), rl); }
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission, callingUid, userId); rl.add(bf);
mReceiverResolver.addFilter(bf); if (allSticky != null) { ArrayList receivers = new ArrayList(); receivers.add(bf); final int stickyCount = allSticky.size(); for (int i = 0; i < stickyCount; i++) { Intent intent = allSticky.get(i); BroadcastQueue queue = broadcastQueueForIntent(intent); BroadcastRecord r = new BroadcastRecord(queue, intent, null, null, -1, -1, null, null, AppOpsManager.OP_NONE, null, receivers, null, 0, null, null, false, true, true, -1); queue.enqueueParallelBroadcastLocked(r); queue.scheduleBroadcastsLocked(); } }}
这里创建ReceiverList对象,并保存到mRegisteredReceivers键值对中,并且创建BroadcastFilter对象保存起来。allSticky为粘性广播队列,如果不为空,粘性广播就会接收到消息。
下面看下发送普通广播流程:
直接进入ContextImpl.java:
ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false, getUserId());
跨进程进入AMS中的broadcastIntent,它里面又调用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); List<BroadcastFilter> registeredReceivers = null; registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false, userId); 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, requiredPermissions, appOp, brOptions, registeredReceivers, resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId); if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r); final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r); if (!replaced) { queue.enqueueParallelBroadcastLocked(r); queue.scheduleBroadcastsLocked(); } registeredReceivers = null; NR = 0; }}
默认添加FLAG_EXCLUDE_STOPPED_PACKAGES标记位,表示停止的应用无法接收到广播。接着通过mReceiverResolver.queryIntent找到之前注册广播保存的BroadcastFilter。因是普通广播,ordered为false。于是获取BroadcastQueue和广播记录BroadcastRecord,接着调用广播队列的enqueueParallelBroadcastLocked:
public void enqueueParallelBroadcastLocked(BroadcastRecord r) { mParallelBroadcasts.add(r); r.enqueueClockTime = System.currentTimeMillis(); }
将广播信息保存在mParallelBroadcasts队列中。接着调用广播队列的scheduleBroadcastsLocked:
public void scheduleBroadcastsLocked() { if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts [" + mQueueName + "]: current=" + mBroadcastsScheduled); if (mBroadcastsScheduled) { return; } mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this)); mBroadcastsScheduled = true; }
可以看到用handler发送消息转到hander中的handleMessage:
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;
进入processNextBroadcast:
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_BROADCAST, "Processing parallel broadcast [" + mQueueName + "] " + r); for (int i=0; i<N; i++) { Object target = r.receivers.get(i); if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Delivering non-ordered on [" + mQueueName + "] to registered " + target + ": " + r); deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i); }
获取之前保存的广播信息,接着进入deliverToRegisteredReceiverLocked:
private void deliverToRegisteredReceiverLocked(BroadcastRecord r, BroadcastFilter filter, boolean ordered, int index) { performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver, new Intent(r.intent), r.resultCode, r.resultData, r.resultExtras, r.ordered, r.initialSticky, r.userId);}
接着进入performReceiveLocked:
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) { 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); // TODO: Uncomment this when (b/28322359) is fixed and we aren't getting // DeadObjectException when the process isn't actually dead. //} catch (DeadObjectException ex) { // Failed to call into the process. It's dying so just let it die and move on. // throw ex; } catch (RemoteException ex) { // Failed to call into the process. It's either dying or wedged. Kill it gently. synchronized (mService) { Slog.w(TAG, "Can't deliver broadcast to " + app.processName + " (pid " + app.pid + "). Crashing it."); app.scheduleCrash("can't deliver broadcast"); } throw ex; } } else { // Application has died. Receiver doesn't exist. throw new RemoteException("app.thread must not be null"); } } else { receiver.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser); } }
这里跨进程进入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); }
这里的receiver是之前客户端传递的InnerReceiver类型binder对象,这里既然已经回到了客户端,那就不需要跨进程了。接着调用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) { Log.wtf(TAG, "Null intent received"); } else { if (ActivityThread.DEBUG_BROADCAST) { int seq = intent.getIntExtra("seq", -1); Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq + " to " + mReceiver); } } if (intent == null || !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); } } } }
这里用handler来post一个runable,接着会走进Args中的run:
public void run() { final BroadcastReceiver receiver = mReceiver; receiver.setPendingResult(this); receiver.onReceive(mContext, intent);}因InnerReceiver中存在ReceiverDispatcher,而ReceiverDispatcher存在BroadcastReceiver对象,因此receiver不为空,调用onReceive就会进入用户自定义的BroadcastReceiver对象中。
- 基于N源码的广播注册和发送流程分析
- Android广播之注册广播(包括静态广播和动态广播的注册)源码分析
- 基于N源码的ContentProvider调用流程分析
- 基于N源码的AccountManagerService简单认识和账户添加流程分析
- Android4.4 Framework分析——广播的注册(BroadcastReceiver)和发送(sendbroadcast)过程分析
- Linux Device和Driver注册过程的源码流程分析
- Android广播之发送广播的源码分析
- Android广播之发送广播的源码分析
- 动态广播注册源码分析
- BroadcastReceiver源码分析系列(二):发送和接收广播
- Android广播管理二--广播注册(registerReceiver)流程分析
- EventBus源码分析(四): 发送Event和响应注册的回调方法
- Android 接收系统发送的广播,动态注册和静态注册
- Android短信发送和接收流程源码分析
- 广播的发送 和 广播的分类
- 广播流程2--发送广播
- BroadcastReceiver注册、发送、接收源码分析
- Android静态注册广播和动态注册广播的区别
- string 构造函数 析构函数
- IE浏览器部分版本不支持background-size属性问题
- centos7和centos6.5环境rpm方式安装mysql5.7和mysql5.6详解
- HDU1021
- Python--python中arange()和linspace()区别
- 基于N源码的广播注册和发送流程分析
- 设计层叠方阵(C语言)
- incomplete type的危害
- vim 查看文件名字和路径方法
- Leetcode刷题记——5. Longest Palindromic Substring
- iOS,一行代码进行RSA、DES 、AES、MD5加密、解密
- Visual Studio(MVC)添加SQL Server数据库
- 83. Remove Duplicates from Sorted List
- day01