内容简介:建议阅读本文之前先阅读早期的时候,广播的特性被各种流氓APP利用.好多好多流氓APP监听比如打电话,收发短信,有些流氓APP甚至直接拦截短信,,当然那个年代早已是过去式了,应该是4.4以前吧,反正以前那会儿挺乱的.现在好多了,想要读取短信内容,难上加难,更不能拦截短信.除非是将APP设置成了默认应用,可以收到短信通知,而且也不能拦截这条广播.以前那会儿即使进程被杀了,只要注册了静态广播,都是能收到的.某些APP收到广播后,就自启,自启后就干些流氓的事情....特别是Android 8.0之后,大部分的静态广
建议阅读本文之前先阅读 死磕Android_Service启动流程分析(一) ,因为有些内容是一致的,方便融合.
早期的时候,广播的特性被各种流氓APP利用.好多好多流氓APP监听比如打电话,收发短信,有些流氓APP甚至直接拦截短信,,当然那个年代早已是过去式了,应该是4.4以前吧,反正以前那会儿挺乱的.现在好多了,想要读取短信内容,难上加难,更不能拦截短信.除非是将APP设置成了默认应用,可以收到短信通知,而且也不能拦截这条广播.以前那会儿即使进程被杀了,只要注册了静态广播,都是能收到的.某些APP收到广播后,就自启,自启后就干些流氓的事情....
特别是Android 8.0之后,大部分的静态广播差不多都失效了.所以我们还是尽量用动态广播比较好,需要的时候注册,不需要的时候解注册.如果只是应用内自己和自己通信,那是么可以使用LocalBroadcastManager的,通信安全.
1. 简单回顾使用方式
定义一个简单的广播
class StaticReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { Log.e("xfhy", "我收到消息了") } } 复制代码
下面是静态注册
需要到清单文件中进行注册
<receiver android:name=".StaticReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="com.xfhy.staticreceiver"/> </intent-filter> </receiver> 复制代码
如果是动态注册,那么需要注册和解注册.
//注册 val intentFilter = IntentFilter() registerReceiver(myBroadcast, intentFilter) //解注册 unregisterReceiver(myBroadcast) 复制代码
注册之后,就可以发广播了
val intent = Intent(applicationContext, StaticReceiver::class.java) intent.action = "com.xfhy.staticreceiver" sendBroadcast(intent) 复制代码
2. 广播注册原理
由于现在基本都用动态广播了(不知道是不是....因为Android 8.0的限制),所以直接讲解动态广播的注册方式.静态注册的方式是通过PMS在应用安装的时候就注册好了,其他3个组件也是.
事不宜迟,我们从registerReceiver方法开始深入,来到ContextWrapper的registerReceiver方法.我们知道Activity是继承了ContextWrapper的.
@Override public Intent registerReceiver( BroadcastReceiver receiver, IntentFilter filter) { return mBase.registerReceiver(receiver, filter); } 复制代码
ContextWrapper几乎是不干实事的,全是交给mBase去做.而mBase是ContextImpl,在Service启动那篇文章中已讲解.
@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(); } } 复制代码
最终会调用registerReceiverInternal方法.而这里有一个IIntentReceiver对象,需要注意.由于在注册的时候是向AMS发起请求需要注册,而BroadcastReceiver是不能进行跨进程传输的,所以需要一个介质.而IIntentReceiver就是专门拿来与AMS通信的,它是一个Binder对象.这里的ReceiverDispatcher和Service绑定流程那里的ServiceDispatcher简直一模一样.ReceiverDispatcher里面有BroadcastReceiver和IIntentReceiver对象,都是在ReceiverDispatcher的构造方法就初始化好了,当收到广播的时候直接调用BroadcastReceiver对象的onReceive方法,简单方便.
来来来,我们看下LoadedApk的getReceiverDispatcher方法
//缓存 private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers = new ArrayMap<>(); 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) { //ReceiverDispatcher初始化,这里会将BroadcastReceiver放进去,然后构造方法会将InnerReceiver(用来跨进程通信的)初始化 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(); } } 复制代码
谷歌工程师写的代码就是牛批,原理几乎一毛一样.
好了,当IIntentReceiver创建好了之后,就可以和AMS进行通信了.上面的ActivityManager.getService()就是AMS哈,在之前的文章经常提到.来到AMS的registerReceiver方法
final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>(); public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String permission, int userId, int flags) { ...... mRegisteredReceivers.put(receiver.asBinder(), rl); BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission, callingUid, userId, instantApp, visibleToInstantApps); mReceiverResolver.addFilter(bf); } 复制代码
上面这个过程会把InnerReceiver(待会儿需要拿来跨进程通信的)和IntentFilter存起来,其实广播的注册就完成了.
3. 广播发送和接收原理
通过sendBroadcast方法发送广播,其实就是在调用的父类ContextWrapper的sendBroadcast方法,之前我们分析过,ContextWrapper本身是不干啥实事的,它其实是调用的ContextImpl的sendBroadcast方法.
@Override public void sendBroadcast(Intent intent) { warnIfCallingFromSystemProcess(); String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); intent.prepareToLeaveProcess(this); ActivityManager.getService().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false, getUserId()); } 复制代码
ActivityManager.getService()是AMS哈,分析过很多次了.这里调用了AMS的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方法了,当我看到这个方法的行数时,我傻眼了,,,大家感受一下.600多行的代码,,,,
我们挑选核心的代码来分析
@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) { // By default broadcasts do not go to stopped apps. //已经停止的APP 无法收到广播 intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES); 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); if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r); final boolean replaced = replacePending && (queue.replaceParallelBroadcastLocked(r) != null); // Note: We assume resultTo is null for non-ordered broadcasts. if (!replaced) { //将符合条件的广播,添加到BroadcastQueue中,然后进行发送 queue.enqueueParallelBroadcastLocked(r); queue.scheduleBroadcastsLocked(); } } 复制代码
我们在源码中可以看到,已经停止了的APP是收不到广播的.然后就是经过一系列的复杂的筛选过程,将符合条件的广播添加到 BroadcastQueue中,然后进行发送广播.
public void scheduleBroadcastsLocked() { ...... //发送了一个消息 mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this)); } private final class BroadcastHandler extends Handler { @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; } } } final void processNextBroadcast(boolean fromMsg) { synchronized (mService) { processNextBroadcastLocked(fromMsg, false); } } final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<>(); final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) { ...... 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); //发送广播这里的r是BroadcastRecord,这个方法里面会调用performReceiveLocked方法 deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i); } addBroadcastToHistoryLocked(r); } } //具体的发送过程 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) { try { //调用ApplicationThread中的scheduleRegisteredReceiver方法 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode, data, extras, ordered, sticky, sendingUser, app.repProcState); } catch (RemoteException ex) { 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); } 复制代码
注意,上面的IIntentReceiver是ReceiverDispatcher中的InnerReceiver对象,这个对象是拿来跨进程通信的.直接调用了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) { Log.wtf(TAG, "Null intent received"); rd = null; } else { rd = mDispatcher.get(); } rd.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser); } 复制代码
其实performReceive就是调用ReceiverDispatcher的performReceive,ReceiverDispatcher是InnerReceiver和BroadcastReceiver的桥梁,因为它里面有两者的引用,可以和方便地进行调用其方法.下面是ReceiverDispatcher的实现
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); } } //注意这句代码 mActivityThread是一个Handler,主线程的Handler, 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); } } } 复制代码
performReceice里面就是利用主线程中的Handler运行一个Runnable.内容如下:
public final Runnable getRunnable() { return () -> { final BroadcastReceiver receiver = mReceiver; final boolean ordered = mOrdered; final IActivityManager mgr = ActivityManager.getService(); final Intent intent = mCurIntent; mCurIntent = null; mDispatched = true; mPreviousRunStacktrace = new Throwable("Previous stacktrace"); if (receiver == null || intent == null || mForgotten) { if (mRegistered && ordered) { if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, "Finishing null broadcast to " + mReceiver); sendFinished(mgr); } return; } Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg"); try { //注意了,BroadcastReceiver是在这个时候进行构建的,构建之后立刻调用它的onReceive方法,注意这是在主线程中调用的 ClassLoader cl = mReceiver.getClass().getClassLoader(); intent.setExtrasClassLoader(cl); intent.prepareToEnterProcess(); setExtrasClassLoader(cl); receiver.setPendingResult(this); receiver.onReceive(mContext, intent); } catch (Exception e) { if (mRegistered && ordered) { if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, "Finishing failed broadcast to " + mReceiver); sendFinished(mgr); } if (mInstrumentation == null || !mInstrumentation.onException(mReceiver, e)) { Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); throw new RuntimeException( "Error receiving broadcast " + intent + " in " + mReceiver, e); } } if (receiver.getPendingResult() != null) { finish(); } Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); }; } 复制代码
可以看到,BroadcastReceiver也是通过反射构建出来的,构建出来之后调用它的onReceive方法,并且是在主线程中调用的.
到这里,广播的发送和接收都已讲解完毕.
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 四大组件的工作过程
- 从宏观的角度看 Gradle 的工作过程
- 前端工程化:围绕Jenkins打造工作流的过程
- 从微服务到工作流:Jet订单系统演变过程分享
- 一篇文章教会你理解Scrapy网络爬虫框架的工作原理和数据采集过程
- 存储过程 – 重新编译后,存储过程运行得很快
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Non-Obvious
Rohit Bhargava / Ideapress Publishing / 2015-3-29 / USD 24.95
What do Disney, Bollywood, and The Batkid teach us about how to create celebrity experiences for our audiences? How can a vending-machine inspire world peace? Can being imperfect make your business mo......一起来看看 《Non-Obvious》 这本书的介绍吧!