不飞则已,一飞冲天;不鸣则已,一鸣惊人。这篇文章主要讲述Android深入四大组件广播的注册发送和接收过程相关的知识,希望能为你提供帮助。
相关文章
Android深入理解四大组件系列
前言
我们接着来学习android四大组件中的BroadcastReceiver,广播主要就是分为注册、接收和发送过程。建议阅读此文前请先阅读Android深入理解四大组件系列的文章,知识重复的部分,本文不再赘述。
1.广播的注册过程
BroadcastReceiver的注册分为两种,分别是静态注册和动态注册,静态注册在应用安装时由PackageManagerService来完成注册过程,关于这一过程,我会在后续的介绍PackageManagerService文章中详细介绍。这里只介绍BroadcastReceiver的动态注册。
要想动态注册BroadcastReceiver,需要调用registerReceiver方法,它的实现在ContextWrapper中,代码如下所示。
frameworks/base/core/java/android/content/ContextWrapper.java
Override
public Intent registerReceiver(
BroadcastReceiver receiver, IntentFilter filter) {
return mBase.registerReceiver(receiver, filter);
}
这里mBase具体指向就是ContextImpl,不明白的请查看Android深入四大组件(二)Service的启动过程这篇文章。ContextImpl的registerReceiver方法有很多重载的方法最终会调用registerReceiverInternal方法:
frameworks/base/core/java/android/app/ContextImpl.java
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context) {
IIntentReceiver rd = null;
if (receiver != null) {
if (mPackageInfo != null &
&
context != null) {//1
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
//2
} else {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = new LoadedApk.ReceiverDispatcher(
receiver, context, scheduler, null, true).getIIntentReceiver();
//3
}
}
try {
final Intent intent = ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission, userId);
//4
if (intent != null) {
intent.setExtrasClassLoader(getClassLoader());
intent.prepareToEnterProcess();
}
return intent;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
在注释1处判断如果LoadedApk类型的mPackageInfo不等于null并且context不等null就调用注释2处的代码通过mPackageInfo的getReceiverDispatcher方法获取rd对象,否则就调用注释3处的代码来创建rd对象。注释2和3的代码的目的都是要获取IIntentReceiver类型的rd对象,IIntentReceiver是一个Binder接口,用于进行跨进程的通信,它的具体实现在
LoadedApk.ReceiverDispatcher.InnerReceiver,如下所示。
frameworks/base/core/java/android/app/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;
}
...
}
...
}
回到registerReceiverInternal方法,在注释4处调用了ActivityManagerProxy(AMP)的registerReceiver方法,最终会调用AMS的registerReceiver方法,并将rd传就去。不明白的同学请查看Android深入四大组件(一)应用程序启动过程(前篇),这里不再赘述。
查看AMS的registerReceiver方法,如下所示。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
...
synchronized(this) {
...
Iterator<
String>
actions = filter.actionsIterator();
//1
...
// Collect stickies of users
int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
while (actions.hasNext()) {
String action = actions.next();
for (int id : userIds) {
ArrayMap<
String, ArrayList<
Intent>
>
stickies = mStickyBroadcasts.get(id);
if (stickies != null) {
ArrayList<
Intent>
intents = stickies.get(action);
if (intents != null) {
if (stickyIntents == null) {
stickyIntents = new ArrayList<
Intent>
();
}
stickyIntents.addAll(intents);
//2
}
}
}
}
}
ArrayList<
Intent>
allSticky = null;
if (stickyIntents != null) {
final ContentResolver resolver = mContext.getContentResolver();
for (int i = 0, N = stickyIntents.size();
i <
N;
i++) {
Intent intent = stickyIntents.get(i);
if (filter.match(resolver, intent, true, TAG) >
= 0) {
if (allSticky == null) {
allSticky = new ArrayList<
Intent>
();
}
allSticky.add(intent);
//3
}
}
}
...
}
注释1处根据传入的IntentFilter类型的filter的得到actions列表,根据actions列表和userIds(userIds可以理解为应用程序的uid)得到所有的粘性广播的intent,并在注释2处传入到stickyIntents中,在注释3处将这些粘性广播的intent存入到allSticky列表中,从这里可以看出粘性广播是存储在AMS中的。
接着查看AMS的registerReceiver方法的剩余内容:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
...
synchronized (this) {
...
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
//1
if (rl == null) {
rl = new ReceiverList(this, callerApp, callingPid, callingUid,
userId, receiver);
//2
if (rl.app != null) {
rl.app.receivers.add(rl);
}
...
}
...
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId);
//3
rl.add(bf);
//4
if (!bf.debugCheck()) {
Slog.w(TAG, "==>
For Dynamic broadcast");
}
mReceiverResolver.addFilter(bf);
//5
...
return sticky;
}
}
注释1处获取ReceiverList列表,如果为空则在注释2处创建,ReceiverList继承自ArrayList,用来存储广播接收者。在注释3处创建BroadcastFilter并传入此前创建的ReceiverList,BroadcastFilter用来描述注册的广播接收者,并在注释4通过add方法将自身添加到ReceiverList中。注释5处将BroadcastFilter添加到mReceiverResolver中,这样当AMS接收到广播时就可以从mReceiverResolver中找到对应的广播接收者了。下面给出广播的注册过程的时序图。
文章图片
2.广播的发送和接收过程
ContextImpl到AMS的调用过程广播可以发送多种类型,包括无序广播(普通广播)、有序广播和粘性广播,这里以无序广播为例,来讲解广播的发送过程。
要发送无序广播需要调用sendBroadcast方法,它的实现同样在ContextWrapper中:
frameworks/base/core/java/android/content/ContextWrapper.java
@Override
public void sendBroadcast(Intent intent) {
mBase.sendBroadcast(intent);
}
【Android深入四大组件广播的注册发送和接收过程】接着来看ContextImpl中的sendBroadcast方法,如下所示。
frameworks/base/core/java/android/app/ContextImpl.java
@Override
public void sendBroadcast(Intent intent) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
getUserId());
//1
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
注释1处又是熟悉的代码,最终会调用AMS的broadcastIntent方法:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
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);
//1
...
/**
* 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处的verifyBroadcastLocked方法:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
final Intent verifyBroadcastLocked(Intent intent) {
// Refuse possible leaked file descriptors
if (intent != null &
&
intent.hasFileDescriptors() == true) {//1
throw new IllegalArgumentException("File descriptors passed in Intent");
}
int flags = intent.getFlags();
//2
if (!mProcessesReady) {
if ((flags&
Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {//3
} else if ((flags&
Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {//4
Slog.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
+ " before boot completion");
throw new IllegalStateException("Cannot broadcast before boot completed");
}
}
if ((flags&
Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
throw new IllegalArgumentException(
"Can‘t use FLAG_RECEIVER_BOOT_UPGRADE here");
}
return intent;
}
verifyBroadcastLocked方法主要是验证广播是否合法,在注释1处验证intent是否不为null并且有文件描述符。注释2处获得intent中的flag。注释3处如果系统正在启动过程中,判断如果flag设置为FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT(启动检查时只接受动态注册的广播接收者)则不做处理,如果不是则在注释4处判断如果flag没有设置为FLAG_RECEIVER_REGISTERED_ONLY(只接受动态注册的广播接收者)则会抛出异常。
我们再回到broadcastIntent方法,在注释2处调用了broadcastIntentLocked方法,代码如下所示。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.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) {
...
if ((receivers != null &
&
receivers.size() >
0)
|| resultTo != null) {
BroadcastQueue queue = broadcastQueueForIntent(intent);
/**
* 1
*/
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, resolvedType,
requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
resultData, resultExtras, ordered, sticky, false, userId);
...boolean replaced = replacePending &
&
queue.replaceOrderedBroadcastLocked(r);
if (!replaced) {
queue.enqueueOrderedBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
//2
}
}
...
}
return ActivityManager.BROADCAST_SUCCESS;
}
这里省略了很多代码,前面的工作主要是将动态注册的广播接收者和静态注册的广播接收者按照优先级高低存储在不同的列表中,再将这两个列表合并到receivers列表中,这样receivers列表包含了所有的广播接收者(无序广播和有序广播)。在注释1处创建BroadcastRecord对象并将receivers传进去,在注释2处调用BroadcastQueue的scheduleBroadcastsLocked方法。
这里先给出ContextImpl到AMS的调用过程的时序图。
文章图片
AMS到BroadcastReceiver的调用过程BroadcastQueue的scheduleBroadcastsLocked方法的代码如下所示。
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
public void scheduleBroadcastsLocked() {
...
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
//1
mBroadcastsScheduled = true;
}
在注释1处向BroadcastHandler类型的mHandler对象发送了BROADCAST_INTENT_MSG类型的消息,这个消息在BroadcastHandler的handleMessage方法中进行处理,如下所示。
frameworks/base/services/core/java/com/android/server/am/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;
...
}
}
}
在handleMessage方法中调用了processNextBroadcast方法,processNextBroadcast方法对无序广播和有序广播分别进行处理,旨在将广播发送给广播接收者,下面给出processNextBroadcast方法中对无序广播的处理部分。
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
final void processNextBroadcast(boolean fromMsg) {
...
if (fromMsg) {
mBroadcastsScheduled = false;
//1
}
// First, deliver any non-serialized broadcasts right away.
while (mParallelBroadcasts.size() >
0) {//2
r = mParallelBroadcasts.remove(0);
//3
...
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);
//4
}
...
}
}
从前面的代码我们得知fromMsg的值为true,因此注释1处会将mBroadcastsScheduled 设置为flase,表示对于此前发来的BROADCAST_INTENT_MSG类型的消息已经处理了。注释2处的mParallelBroadcasts列表用来存储无序广播,通过while循环将mParallelBroadcasts列表中的无序广播发送给对应的广播接收者。在注释3处获取每一个mParallelBroadcasts列表中存储的BroadcastRecord类型的r对象。注释4处将这些r对象描述的广播发送给对应的广播接收者,deliverToRegisteredReceiverLocked方法如下所示。
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
BroadcastFilter filter, boolean ordered, int index) {
...
try {
if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,
"Delivering to " + filter + " : " + r);
if (filter.receiverList.app != null &
&
filter.receiverList.app.inFullBackup) {
...
} else {
performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode, r.resultData,
r.resultExtras, r.ordered, r.initialSticky, r.userId);
//1
}
if (ordered) {
r.state = BroadcastRecord.CALL_DONE_RECEIVE;
}
} catch (RemoteException e) {
...
}}
这里省去了大部分的代码,这些代码是用来检查广播发送者和广播接收者的权限。如果通过了权限的检查,则会调用注释1处的performReceiveLocked方法:
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
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) {//1
if (app.thread != null) {//2
// 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);
//3
}
}
...
} else {
receiver.performReceive(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
/
}
}
注释1和2处的代码表示如果广播接收者所在的应用程序进程存在并且正在运行,则执行注释3处的代码,表示用广播接收者所在的应用程序进程来接收广播,这里app.thread指的是ApplicationThread,我们来查看ApplicationThread的scheduleRegisteredReceiver方法,代码如下所示。
frameworks/base/core/java/android/app/ActivityThread.java
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);
//1
}
注释1处调用了IIntentReceiver类型的对象receiver的performReceive方法,这里实现receiver的类为LoadedApk.ReceiverDispatcher.InnerReceiver,代码如下所示。
frameworks/base/core/java/android/app/LoadedApk.java
static final class ReceiverDispatcher {
final static class InnerReceiver extends IIntentReceiver.Stub {
...
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 (rd != null) {
rd.performReceive(intent, resultCode, data, extras,
ordered, sticky, sendingUser);
//1
} else {
...
}
...
}
在注释1处调用了ReceiverDispatcher类型的rd对象的performReceive方法:
frameworks/base/core/java/android/app/LoadedApk.java
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);
//1
...
if (intent == null || !mActivityThread.post(args)) {//2
if (mRegistered &
&
ordered) {
IActivityManager mgr = ActivityManagerNative.getDefault();
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对象通过H发送到主线程的消息队列中。Args继承自Runnable,这个消息最终会在Args的run方法执行,Args的run方法如下所示。
frameworks/base/core/java/android/app/LoadedApk.java
public void run() {
...
try {
ClassLoader cl =mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
intent.prepareToEnterProcess();
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
//1
} catch (Exception e) {
...
}
...
}
在注释1处执行了广播接收者的onReceive方法,这样注册的广播接收者就收到了广播并得到了intent。
广播的注册、发送和接收过程就讲到这,最后给出剩余部分的调用时序图。
文章图片
欢迎关注我的微信公众号,第一时间获得博客更新提醒,以及更多成体系的Android相关原创技术干货。
扫一扫下方二维码或者长按识别二维码,即可关注。
文章图片
推荐阅读
- ASR Now Supports NetApp Private Storage for Microsoft Azure
- 浅析WPhoneAndroid的Back与Home键
- App软件开发的完整在线流程(一看就懂)
- android(如何通过自定义工程模板让新建的工程都默认支持lambda表达式)
- Android 学习之逐帧动画(Frame)
- 如何通过SSH连接到正在运行的Docker容器并运行命令()
- Docker镜像与容器有什么区别(它们有什么关系?)
- Docker ADD与COPY有什么区别(应该该使用哪个?)
- 6个Kubernetes安全最佳方式(保护你的工作负载)