本章介绍BroadcastReceiver的工作过程,主要包含两方面的内容,一个是广播的注册过程,另一个是广播的发送和接收过程。
一、BroadcastReceiver的使用
这里简单回顾下广播的使用方法:
class MyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
//onReceive函数不能做耗时的事情,参考值:10s以内
String action = intent.getAction();
Log.d(TAG,"on receive action=" + action);
//do your works
}
}
定义好了广播接收者,接着还需要注册广播接收者,注册分为两种方式,AndroidManifest文件中静态注册,也可以通过代码动态注册。
- 静态注册的示例如下:
<receiver android:name="com.example.broadcast.MyReceiver">
<intent-filter>
<action android:name="com.example.receiver.LANUCH"/>
</intent-filter>
</receiver>
- 代码注册示例如下:
IntentFilter filter = new IntentFilter();
filter.addAction("com.example.receiver.LANUCH");
registerReceiver(new MyReceiver(),filter);
需要注意的是,动态注册的广播需要在合适的时机进行解注册,解注册采用unregisterReceiver方法。
- send发送广播
Intent intent = new Intent();
intent.setAction("com.example.receiver.LANUCH");
sendBroadcast(intent);
下面开始分析广播的工作过程。代码都是基于Android8.1的,可能部分和书上不太一样。但差别很小(比如我们代码获取AMS是通过getService这个方法)。
二、广播的注册过程
//android.content.ContextWrapper#registerReceiver
@Override
public Intent registerReceiver(
BroadcastReceiver receiver, IntentFilter filter) {
return mBase.registerReceiver(receiver, filter);
}
ContextImpl的registerReceiver方法调用自己的registerReceiverInternal方法
//android.app.ContextImpl#registerReceiverInternal
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();
}
}
//android.app.LoadedApk#getReceiverDispatcher
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) {
rd = new ReceiverDispatcher(r, context, handler,
instrumentation, registered);
if (registered) {
if (map == null) {
//可以看到这个和service很像。也是通过一个ArrayMap保存注册的广播
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();
}
}
由于注册广播的真正实现过程是在AMS中,因此我们需要看下AMS的具体实现。AMS的registerReceiver方法看起来很长,其实关键的就只有下面一部分,最终会把远程的InnerReceiver对象以及IntentFilter对象存储起来,这样整个广播的注册过程就完成了
//com.android.server.am.ActivityManagerService#registerReceiver
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);
rl.add(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadcast");
}
mReceiverResolver.addFilter(bf);
...
}
注册就分析完成了。
三、广播的发送和接收
//android.app.ContextImpl#sendBroadcast
@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();
}
}
和前面分析一样,通过Binder IPC调用到AMS的sendBroadcast
//com.android.server.am.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) {
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;
}
}
从上面的代码看,broadcastIntent调用了broadcastIntentLocked方法,AMS的broadcastIntentLocked方法中有一行:
// By default broadcasts do not go to stopped apps.
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
在broadcastIntentLocked的内部,会根据intent-filter查找出匹配的广播接收者并经过一系列的条件过滤,最终会将满足条件的广播接收者添加到BroadcastQueue中,接着BroadcastQueue就会将广播发送给相应的广播接收者,代码如下:
//com.android.server.am.ActivityManagerService#broadcastIntentLocked 代码片段
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
if (!ordered && NR > 0) {
if (isCallerSystem) {
checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
isProtectedBroadcast, registeredReceivers);
}
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) {
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();//调用到发送广播方法
}
registeredReceivers = null;
NR = 0;
}
BroadcastQueue的发送实现如下
//com.android.server.am.BroadcastQueue#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;
}
BroadcastQueue的scheduleBroadcastsLocked方法并没有立即发送广播,而是发送了BROADCAST_INTENT_MSG类型的消息,消息的处理会调用processNextBroadcast方法
//com.android.server.am.BroadcastQueue#processNextBroadcast 代码片段
while (mParallelBroadcasts.size() > 0) {
r = mParallelBroadcasts.remove(0);
r.dispatchTime = SystemClock.uptimeMillis();
r.dispatchClockTime = System.currentTimeMillis();
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),
System.identityHashCode(r));
Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),
System.identityHashCode(r));
}
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);//具体的发送方法,给每个接收者发送
}
addBroadcastToHistoryLocked(r);
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
+ mQueueName + "] " + r);
}
可以看到,无序广播存储在mParallelBroadcasts中,系统会遍历mParallelBroadcasts并将其中的广播发送给它们所有的接收者,具体的发送过程是通过deliverToRegisteredReceiverLocked方法来实现的。
//com.android.server.am.BroadcastQueue#deliverToRegisteredReceiverLocked 代码片段
performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode, r.resultData,
r.resultExtras, r.ordered, r.initialSticky, r.userId);
performReceiveLocked方法实现如下。由于接收广播会调起应用程序,因此app.thread不为null,前面分析知道app.thread就是ApplicationThread。
//com.android.server.am.BroadcastQueue#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);//看到这里就调回了ApplicationThread中了
} catch (RemoteException ex) {
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中了,看看ApplicationThread#scheduleRegisteredReceiver方法
//android.app.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);
}
InnerReceiver的performReceive方法又会调用LoadApk.ReceiverDispatcher的performReceive方法,具体实现:
//android.app.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) {
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.getRunnable())) {//将args的runnable post主线程执行
if (mRegistered && ordered) {
IActivityManager mgr = ActivityManager.getService();
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing sync broadcast to " + mReceiver);
args.sendFinished(mgr);
}
}
}
分析完成,可以发现广播的注册,发送,接收和Service的启动很类似。都是IPC和AMS交互。