BroadcastReceiver
博文来源于
BroadcastReceiver探讨之动态广播注册流程
csdn:linyh1992
源码:
frameworks/base/+/android-4.4.1_r1/core/java/android/app/ContextImpl.java
frameworks/base/+/android-4.4.1_r1/core/java/android/app/ActivityManagerNative.java
frameworks/base/+/android-4.4.1_r1/services/java/com/android/server/am/ActivityManagerService.java
frameworks/base/+/android-4.4.1_r1/core/java/android/app/LoadedApk.java
frameworks/base/+/android-4.4.1_r1/services/java/com/android/server/am/ReceiverList.java
frameworks/base/+/android-4.4.1_r1/services/java/com/android/server/am/BroadcastFilter.java
在Android中,BroadcastReceiver是一套用来实现组件之间的通信机制,它是基于消息发布和订阅机制,可以用在不同线程之间组件的通信,也可以跨进程进行组件间通信。
在Android中,根据注册类型来看,BroadcastReceiver可以分为两种类型:静态广播和动态广播,其中静态广播中的广播中心是PMS(PackageManagerService),而动态广播的广播中心是AMS(ActivityManagerService),这边文章主要是分析动态广播的。
动态BroadcastReceiver的注册是借助Context接口中的registerReceiver方法来实现的。其中,继承Context接口的类有:Activity,Service,Application,所以在这3个类中,都可以动态注册广播。此外,Context接口的实现类,是ContextImpl类。
在讨论BroadcastReceiver前,需要稍微了解下Android不同进程之间的通信,以及一些Android系统级的Service。
Android跨进程之间的通信,主要有Binder实现的IPC机制,匿名共享内存,socket等等,而广播的跨进程通信是使用Binder来实现的,通过Binder将App进程切换到system_server进程和AMS通信。
在手机开机的时候,Android启动了很多系统级的进程,比如zygote进程,system_server进程,其中在system_server进程上,又启动了很多服务,
比如PowerManagerService(电源管理服务),ActivityManagerService(管理四大组件)
下面,主要是通过探讨广播,主要是分为两部分,
用户进程和system_server进程,广播registerReceiver的流程
用户进程和system_server进程,广播底层的数据存储结构
Context.java
public abstract Intent registerReceiver(BroadcastReceiver receiver,IntentFilter filter);
receiver: 广播接收组件,接收到相关的广播会调用BroadcastReceiver中的onReceive方法
filter:主要是用来过滤广播的,只有符合条件的广播才会接收.
registerReceiver方法最终是调用ContextImpl中的registerReceiverInternal方法
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) {
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 {
return ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission, userId);
} catch (RemoteException e) {
return null;
}
}
mPackageInfo:LoadedApk类型,保存了整个App内部的信息,比如包名,资源的路径,应用中所有启动的service,注册的reciver等等,用户进程(即一个应用进程)中,只会存在一个对象,所有ContextImpl中的mPackageInfo都指向共同的mPackageInfo对象,因此,mPackageInfo在整个用户进程中是唯一的。
registerReceiverInternal方法:
1,获取Handler类型的scheduler对象,如果scheduler不为null,则scheduler为用户传递进来的Handler,否则为主线程中的Hanlder(这也是为什么BroadcastReceiver中的onReceive方法调用是处于主线程的原因),这个Handler对象主要是用来分发AMS传递过来的Intent,
2,如果mPackageInfo存在,则通过mPackageInfo获取IIntentReceiver类型的rd对象,否则创建一个,rd同样也是Binder类型。然后,将rd传递给AMS,AMS处理相对应的广播,会通过这个Binder对象,跨进程回传到这个Context所处的进程中。
3,通过ActivityManagerNative.getDefault()获取到ActivityManagerProxy对象,然后借助ActivityManagerProxy对象,和AMS通信,这时候进程由用户进程切换到system_server进程,最终调用的是AMS中的registerReceiver方法。
scheduler = mMainThread.getHandler();
mMainThread是ActivityThread对象,也可以说是主线程
这里有个疑惑,关于mPackageInfo,这个对象什么时候不存在?(以后再查看)按照我目前的理解,mPackageInfo最早是在Application创建的时候,就被初始化了,而context是当前的Activity,Service或者Application,所以符合条件(mPackageInfo != null && context != null)
rd = mPackageInfo.getReceiverDispatcher(receiver, context, scheduler, mMainThread.getInstrumentation(), true);
LoadedApk
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) {
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();
}
}
1,如果广播已经注册过,则通过mReceivers对象获取key为当前Context的LoadedApk.ReceiverDispatcher类型的rd对象
2,如果rd对象不存在,则创建,并且将rd添加到map中;否则,验证rd对象中的context和activitythread(validate这个方法有疑惑,什么场景下,rd中context和activitythread和目前的不一致)
3,返回rd对象的中IIntentReceiver对象
上面说过,在用户进程中所有ContextImpl中的mPackageInfo都指向同一对象。
mPackageInfo中存在维持一个ArrayMap的mReceivers变量,mReceivers是ArrayMap嵌套ArrayMap的数据结构
key:为注册的Context(即Activity,Service或者Application),
value:同样也是个ArrayMap,
key:注册的BroadcastReceiver
value:ReceiverDispatcher对象,广播分发者,该对象内部保存注册者的Context,Handler,BroadcastReceiver,IIntentReceiver.Stub(和用户进程交互的)等等,
发送广播时,AMS将会将Intent信息分发到BroadcastReceiver的onRecieve方法中。
mReceivers
private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
= new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
LoadedApk.ReceiverDispatcher
final IIntentReceiver.Stub mIIntentReceiver;
final BroadcastReceiver mReceiver;
final Context mContext;
final Handler mActivityThread;
final Instrumentation mInstrumentation;
final boolean mRegistered;
final IntentReceiverLeaked mLocation;
RuntimeException mUnregisterLocation;
//....
try {
// 跨进程和AMS通信,广播的注册实际上是在AMS中执行的
return ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission, userId);
} catch (RemoteException e) {
return null;
}
ActivityManagerNative.getDefault()
public abstract class ActivityManagerNative extends Binder implements IActivityManager {
// ...省略
// 获取到唯一的
static public IActivityManager getDefault() {
return gDefault.get();
}
// ...省略
// Singleton是一个抽象类,Android实现的单例模式
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
// 获取指向ActivityManagerService的IBinder对象
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
// 创建ActivityManagerProxy对象,并将ActivityManagerService的Binder传递给ActivityManagerProxy
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
// 创建一个ActivityManagerProxy对象
static public IActivityManager asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IActivityManager in =
(IActivityManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ActivityManagerProxy(obj);
}
}
ActivityManagerNative.getDefault()第一次会创建一个AMP(ActivityManagerProxy)对象,并通过ServiceManager远程获取到一个指向AMS
的IBinder对象,并将这个IBinder引用传递给AMS对象,最后返回AMP对象,注意这个对象运行在用户进程中的,
ActivityManagerProxy中的IBinder引用是用来跨进程和AMS通信的。
ActivityManagerProxy.registerReceiver
public Intent registerReceiver(IApplicationThread caller, String packageName,
IIntentReceiver receiver,
IntentFilter filter, String perm, int userId) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(packageName);
data.writeStrongBinder(receiver != null ? receiver.asBinder() : null);
filter.writeToParcel(data, 0);
data.writeString(perm);
data.writeInt(userId);
// 跨进程和AMS通信,注意Binder驱动会挂起当前用户线程
mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);
reply.readException();
Intent intent = null;
int haveIntent = reply.readInt();
if (haveIntent != 0) {
intent = Intent.CREATOR.createFromParcel(reply);
}
reply.recycle();
data.recycle();
return intent;
}
很明显,这段代码是用来跨进程通信的。mRemote是一个IBinder对象,指向AMS的。
mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);
Binder机制非常复杂,这里不做讨论。我们只需要知道IBinder.transact方法,会调用到IBinder.onTransact方法。
题外话:
这里有个疑惑,mRemote.transact会不会阻塞线程呢?仔细思考了下,应该会的,准确的来说,Binder驱动会挂起当前用户进程。
因为registerReceiver返回Intent对象,如果当前用户线程没有挂起的话,那么后面的代码就没意义了,比如reply.readException肯定没效果。
mRemote这个IBinder对象是指向AMS的,而AMS继承了ActivityManagerNative类,并且AMS的onTransact方法是由ActivityManagerNative实现的。
ActivityManagerNative.onTransact,注意调用这个方法的时候,进程已经从用户进程切换到system_server进程了。
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
case REGISTER_RECEIVER_TRANSACTION:
{
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
IApplicationThread app =
b != null ? ApplicationThreadNative.asInterface(b) : null;
String packageName = data.readString();
b = data.readStrongBinder();
IIntentReceiver rec
= b != null ? IIntentReceiver.Stub.asInterface(b) : null;
IntentFilter filter = IntentFilter.CREATOR.createFromParcel(data);
String perm = data.readString();
int userId = data.readInt();
// 调用AMS中的registerReceiver方法,这个方法是广播注册的最终实现
Intent intent = registerReceiver(app, packageName, rec, filter, perm, userId);
reply.writeNoException();
if (intent != null) {
reply.writeInt(1);
intent.writeToParcel(reply, 0);
} else {
reply.writeInt(0);
}
return true;
}
}
ActivityManagerService.registerReceiver
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
enforceNotIsolatedCaller("registerReceiver");
int callingUid;
int callingPid;
synchronized(this) {
ProcessRecord callerApp = null;
if (caller != null) {
callerApp = getRecordForAppLocked(caller);
if (callerApp == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when registering receiver " + receiver);
}
if (callerApp.info.uid != Process.SYSTEM_UID &&
!callerApp.pkgList.containsKey(callerPackage) &&
!"android".equals(callerPackage)) {
throw new SecurityException("Given caller package " + callerPackage
+ " is not running in process " + callerApp);
}
callingUid = callerApp.info.uid;
callingPid = callerApp.pid;
} else {
callerPackage = null;
callingUid = Binder.getCallingUid();
callingPid = Binder.getCallingPid();
}
userId = this.handleIncomingUser(callingPid, callingUid, userId,
true, true, "registerReceiver", callerPackage);
List allSticky = null;
// Look for any matching sticky broadcasts...
Iterator actions = filter.actionsIterator();
if (actions != null) {
while (actions.hasNext()) {
String action = (String)actions.next();
allSticky = getStickiesLocked(action, filter, allSticky,
UserHandle.USER_ALL);
allSticky = getStickiesLocked(action, filter, allSticky,
UserHandle.getUserId(callingUid));
}
} else {
allSticky = getStickiesLocked(null, filter, allSticky,
UserHandle.USER_ALL);
allSticky = getStickiesLocked(null, filter, allSticky,
UserHandle.getUserId(callingUid));
}
// The first sticky in the list is returned directly back to
// the client.
Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
if (DEBUG_BROADCAST) Slog.v(TAG, "Register receiver " + filter
+ ": " + sticky);
if (receiver == null) {
return sticky;
}
ReceiverList rl
= (ReceiverList)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);
} else if (rl.uid != callingUid) {
throw new IllegalArgumentException(
"Receiver requested to register for uid " + callingUid
+ " was previously registered for uid " + rl.uid);
} else if (rl.pid != callingPid) {
throw new IllegalArgumentException(
"Receiver requested to register for pid " + callingPid
+ " was previously registered for pid " + rl.pid);
} else if (rl.userId != userId) {
throw new IllegalArgumentException(
"Receiver requested to register for user " + userId
+ " was previously registered for user " + rl.userId);
}
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId);
rl.add(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadast");
}
mReceiverResolver.addFilter(bf);
// Enqueue broadcasts for all existing stickies that match
// this filter.
if (allSticky != null) {
ArrayList receivers = new ArrayList();
receivers.add(bf);
int N = allSticky.size();
for (int i=0; i<N; i++) {
Intent intent = (Intent)allSticky.get(i);
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
null, -1, -1, null, null, AppOpsManager.OP_NONE, receivers, null, 0,
null, null, false, true, true, -1);
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
}
return sticky;
}
}
1,首先会获取应用的uid和pid,然后调用handleIncomingUser检测注册广播所需的权限,并获取userId
2,检测所有符合条件的黏性事件,如果广播为null,则返回最近的一条黏性事件
3,通过mRegisteredReceivers获取key为receiver(IBinder对象,从用户进程中传递进来的IIntentReceiver对象),获取相关的ReceiverList;
如果ReceiverList为null,则创建,并添加到mRegisteredReceivers中
4,创建BroadcastFilter(继承IntentFilter)对象,并添加进入到ReceiverList中
5,处理符合条件的黏性事件(这里暂不探讨)
ReceiverList:继承ArrayList,存储的是BroadcastFilter对象
BroadcastFilter:继承IntentFilter,主要是用来过滤广播的,广播接收器只能接收指定的广播类型
AMS中维持一个mRegisteredReceivers变量的HashMap
final HashMap<IBinder, ReceiverList> mRegisteredReceivers =
new HashMap<IBinder, ReceiverList>();
mRegisteredReceivers的数据结构是HashMap
key:IBinder,也就是ReceiverDispatcher中的IIntentReceiver对象,是用于AMS和用户进程通信的
value:ReceiverList,存储一系列的BroadcastFilter的List
mReceiverResolver:存储对应的BroadcastFilter
参考:
Android应用程序注册广播接收器(registerReceiver)的过程分析
四大组件的工作过程
Android中Context详解 —- 你所不知道的Context
品茗论道说广播(Broadcast内部机制讲解)(上)
Android 内核–Context对象