100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > [.07.12]Android系统广播机制(Broadcast Receiver)

[.07.12]Android系统广播机制(Broadcast Receiver)

时间:2021-11-15 04:47:43

相关推荐

[.07.12]Android系统广播机制(Broadcast Receiver)

广播(Broadcast)是一种在组件之间进行消息传递的方式。这些组件可以运行在同一个进程中,也可以在不同的进程中。事实上,广播机制就是在Binder进程间通信的基础上实现的。那么,有了Binder通信Android系统为什么还需要广播机制呢?在Binder通信时,Client端在和Server端通信前要先获得Server端的一个代理。而在广播中,发送者是不需要知道接收者是否存在的,这降低了发送者和接收者之间的耦合度。所以Android系统需要广播机制。

Android系统将广播接收者抽象为一种Broadcast Receiver组件,是Android应用程序的四大组件之一。另外两种组件,Activity组件和Service组件被赋予了发送广播的能力。广播机制存在一个注册中心,由ActivityManagerService来担当。广播接收者会先将自己注册到AMS中,并指定要接收的广播的类型。当广播发送者发送一个广播时,先发送到AMS,然后AMS根据广播类型找到对应的广播接收者,最后将广播发送给接收者处理。

广播接收者的注册方式分为静态注册和动态注册两种。静态注册中,需要在配置文件AndroidManifest.xml注明它们感兴趣的广播类型,以便AMS可以找到它们。动态注册中,需要调用Context接口的成员函数registerReceiver将Broadcast Receiver组件注册到AMS中。动态注册的广播接收者的优先级高于静态注册的广播接收者。

广播的发送分为有序和无序两种。注册广播时可以指定它们的优先级,当AMS接收到有序广播时,AMS会按照优先级将广播发送给接收者处理;当AMS接收到无序广播时,忽略优先级将广播发送给接收者处理。

1 广播机制应用实例

Broadcounter应用程序

ICounterService.java

public interface ICounterService {public void startCounter(int initVal);public void stopCounter();}

CounterService.java

public class CounterService extends Service implements ICounterService {public final static String BROADCAST_COUNTER_ACTION = "broadcounter.COUNTER_ACTION";public final static String COUNTER_VALUE = "broadcounter.counter.value"......public void startCounter(int initVal) {AsyncTask<Integer, Integer, Integer> task = new AsyncTask<Integer, Integer, Integer>() {@Overrideprotected Integer doInBackground(Integer... vals) {Integer initCounter = vals[0];stop = false;while (!stop) {// 每隔1s计数器+1publishProgress(initCounter);try {Thread.sleep(1000);} catch (InterruptedExcepiton e) {e.printStackTrace();}initCounter++;}return initCounter;} @Overrideprotected void onProgressUpdate(Integer... values) {super.onProgressUpdate(values);int counter = values[0];Intent intent = new Intent(BROADCAST_COUNTER_ACTION);intent.putExtra(COUNTER_VALUE, counter);sendBroadcast(intent);}@Overrideprotected void onPostExecute(Integer val) {int counter = val;Intent intent = new Intent(BROADCAST_COUNTER_ACTION);intent.putExtra(COUNTER_VALUE, counter);sendBroadcast(intent);}};task.execute(initVal);}public void stopCounter() {stop = true;}}

通过异步任务AsyncTask来提供计数器功能,通过CounterService父类ContextWrapper的成员函数sendBroadcast发送广播,以便Broadcounter组件可以接收到这个广播,获取计数值。

Broadcounter.java

public class Broadcounter extends Activity implements OnClickListener {@Overridepublic void onResume() {super.onResume();IntentFilter counterActionFilter = new IntentFilter(CounterService.BROADCAST_COUNTER_ACTION);registerReceiver(counterActionReceiver, counterActionFilter);}@Overridepublic void onPause() {super.onPause();unregisterReceiver(counterActionReceiver);}private BroadcastReveiver counterActionReceiver = new BroadcastReceiver() {public void onReceive(Context context, Intent intent) {int counter = intent.getIntExtra(CounterService.COUNTER_VALUE, 0);String text = String.valueOf(counter);counterText.setText(text);}};}

Broadcounter组件定义了一个广播接收者counterActionReceiver,它用来接收类型为BROADCAST_COUNTER_ACTION的广播,以便计算当前计数值。

Broadcounter组件激活时,调用父类ContextWrapper的registerReceiver函数将广播接收者counterActionReceiver注册到AMS中。

Broadcounter组件被中止时,调用父类ContextWrapper的unregisterReceiver函数将广播接收者counterActionReceiver从AMS中注销。

编译:

mmm ./packages/experimental/Broadcouner

/out/target/product/generic/system/app生成Broadcouner.apk

打包:

make snod

/out/target/product/generic生成system.img

测试:

emulator

2 广播接收者的注册过程

广播接收者的注册过程如下:

图2广播接收者的注册过程

(1)Broadcounter.onResume

packages/experimental/.../Broadcounter.java

public class Broadcounter extends Activity implements OnClickListener {@Overridepublic void onResume() {super.onResume();IntentFilter counterActionFilter = new IntentFilter(CounterService.BROADCAST_COUNTER_ACTION);registerReceiver(counterActionReceiver, counterActionFilter);}...... private BroadcastReveiver counterActionReceiver = new BroadcastReceiver() {public void onReceive(Context context, Intent intent) {int counter = intent.getIntExtra(CounterService.COUNTER_VALUE, 0);String text = String.valueOf(counter);counterText.setText(text);}};}

要接收的广播类型为BROADCAST_COUNTER_ACTION。

(2)ContextWrapper.registerReceiver

frameworks/base/core/java/android/content/ContextWrapper.java

public class ContextWrapper extends Context {Context mBase;......@Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {return mBase.registerReceiver(receiver, filter);}}

mBase指向一个ContextImpl对象。

(3)ContextImpl.registerReceiver

frameworks/base/core/java/android/app/ContextImpl.java

class ContextImpl extends Context {// 默认包访问控制/*package*/ LoadedApk mPackageInfo;/*package*/ ActivityThread mMainThread;private Context mOuterContext;......@Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {return registerReceiver(receiver, filter, null, null);}@Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,String broadcastPermisssion, Handler scheduler) {return registerReceiverInternal(receiver, filter, broadcastPermission, scheduler, getOuterContext());}private Intent registerReceiverInternal(BroadcastReceiver receiver, IntentFilter filter,String broadcastPermisssion, 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);}......}try {return ActivityManagerNative.getDefault().registerReceiver(mMainThread.getApplicationThread(), rd, filter, broadcastPermission);} catch (RemoteException e) {return null;}}}

getReceiverDispatcher函数将广播接收者receiver封装成一个实现了IIntentReceiver接口的Binder本地对象rd。

ActivityManagerNative.getDefault()返回AMS的代理对象。registerReceiver函数将Binder本地对象rd,IntentFilter对象等信息发送给AMS,AMS可以将rd注册在内部,将IntentFilter对象描述的广播转发处理。

成员mMainThread用来描述当前应用程序进程的,getHandler()返回的Handler对象用来向进程主线程的消息队列发送消息。一个广播到达对应的广播接收者应用程序进程时,首先会封装成一个消息,然后再发送到该应用程序进程主线程的消息队列中,最后才会分发给广播接收者处理。

getOuterContext()返回的是成员mOuterContext,指向的是一个Activity组件,这里是指Broadcounter组件。这样registerReceiverInternal就把广播接收者receiver和Broadcouner组件联系到了一起。

frameworks/base/core/java/android/app/LoadedApk.java

final class LoadedApk {public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r, Context context, Handler handler,Instrumentation instrumentation, boolean registered) {synchronized (mReceivers) {// rd是RevevierDispatcher的缩写LoadedApk.ReceiverDispatcher rd = null;HashMap<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 (registerd) {if (map == null) {map = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();mReceivers.put(context, map);}}} else {rd.validate(context, handler);}return rd.getIIntentReceiver();}} ...}

每一个注册过广播接收者的Activity组件在LoadedApk类中都有一个对应的ReceiverDispatcher对象,它负责将这个被注册的广播接收者与Acitivity组件关联在一起。LoadedApk.ReceiverDispatcher通过map与BroadcastReceiver关联,map通过mReceivers与Activity组件的context关联。

rd.getIIntentReceiver()用来获得一个实现了IIntentReceiver接口的Binder本地对象。

frameworks/base/core/java/android/app/LoadApk.java

final class LoadedApk {static final class ReceiverDispatcher {final static class InnerReceiver extends IIntentReceiver.Stub {final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;......InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {mDispatcher = new WeakReferance<LoadedApk.ReceiverDispatcher>(rd);......}}......final IIntentReceiver.Stub mIIntentReceiver;final BroadcastReceiver mReceiver;final Context mContext;final Handler mActivityThread;......ReceiverDispatcher(BroadcastReceiver receiver, Context context, Handler activityThread, Instrumentation instrumentation, boolean registered) {......mIIntentReceiver = new InnerReceiver(this, !registered);mReceiver = receiver;mContext = context;mActivityThread = activityThread;......}IIntentReceiver getIIntentReceiver() {return mIIntentReceiver;}}}

弱引用mDispatcher指向了一个外部的ReceiverDispatcher对象。

mIIntentReceiver指向一个实现了IIntentReceiver接口的本地对象。mContext指向了一个Activity组件,mActivityThread和mReceiver分别指向了与该Activity组件相关联的一个Handler对象和一个广播接收者。例如,Broadcounter组件在注册广播接收者counterActionReceiver时,LoadedApk类会为它创建一个ReceiverDispatcher对象,这个对象的成员mContext,mReceiver和mActivityThread分别指向了Broadcounter组件,Broadcounter组件的广播接收者counterActionReceiver和Broadcounter组件所在进程的主线程的一个Handler对象。

回到ContextImpl的registerReceiverInternal中,它将广播接收者receiver封装成一个InnerReceiver对象后,将这个InnerReceiver对象注册到AMS中了。

(4)ActivityMangerProxy.registerReceiver

frameworks/base/core/java/android/app/ActivityManagerNative.java

class ActivityManagerProxy implements IActivityManager {public IIntent registerReceiver(IApplicationThread caller, IIntentReceiver receiver, IntentFilter filter, String perm) throws RemoteException {Parcel data = Parcel.obtain();Parcel reply = Parcel.obtain();data.writeInterfaceToken(IActivityManger.descriptor);data.writeStrongBinder(caller != null ? caller.asBinder() : null);data.writeStrongBinder(receiver != null ? receiver.asBinder() : null);filter.writeToParcel(data, 0);data.writeString(perm);mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);reply.readExceptinon();Intent intent = null; int haveIntent = reply.readInt();if (haveIntent != 0) {intent = Intent.CREATOR.createFromParcel(reply);}reply.recycle();data.recycle();return intent;}......}

mRemote是ActivityManagerProxy类内部的一个Binder代理对象。

以上4步都是在应用程序Broadcounter中执行的,下面第5步是在AMS中执行的。

(5)ActivityMangerService.registerReceiver

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

public final class ActivityManagerService extends ActivityManagerNatice implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {public Intent registerReceiver(IApplicationThread caller, IIntentReceiver receiver, IntentFilter filter, String permission) {sychonized(this) {ProcessRecord callerApp = null;if (caller != null) {callerApp = getRecordForAppLocked(caller);......}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);}}......// The first sticky in the list is returned directly back to the clientIntent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;......ReceiverList rl = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());if (rl == null) {rl = new ReceiverList(this, callerApp, Binder.getCallingPid(), Binder.getCallingUid(), receiver);......mRegisteredReceiver.put(receiver.asBinder(), rl);}BroadcastFiler bf = new BroadcastFiler(filter, rl, permission);rl.add(bf);mReceiverResolver.addFiler(bf);......return sticky;}}......}

AMS的registerReceiver函数用来处理类型为REGISTER_RECEIVER_TRANSACTION的进程间通信请求。

ProcessRecord对象callerApp,用来描述正在请求AMS注册广播接收者的一个Activity组件所运行的应用程序进程。

sticky broadcast:什么是黏性广播呢?一个黏性广播被发送到AMS后,就会一直保存在AMS中,直到AMS下次再接收到同类型的黏性广播为止。一个Activity组件在向AMS注册广播时,如果AMS内部恰好保存这种类型的黏性广播,那么AMS会将这个黏性广播返回给这个Activity组件,以便可以知道上一次广播的内容。可以通过Activity组件或Service组件的父类ContextWrapper的sendStickyBroadcast向AMS发送一个黏性广播。

当AMS接收到一个广播时,它就会根据这个广播的类型在内部(mReceiverResolver)找到对应的InnerReceiver对象,然后再通过此InnerReceiver对象将这个广播发送给对应的广播接收者处理。

3 广播的发送与处理过程

(1)(2)发送,(3)(4)处理:

(1)广播发送者,即一个Activity组件或一个Service组件,将一个特定类型的广播发送给AMS。

(2)AMS接收到一个广播后,首先找到与这个广播对应的广播接收者,然后将它们添加到一个广播调度队列里,最后向AMS所在的线程的消息队列发送一个类型为BROADCAST_INTENT_MSG的消息。这时候对广播发送者来说,一个广播就发送完了。

(3)当AMS所在线程的消息队列中的BROADCAST_INTENT_MSG消息被处理时,AMS就会从广播调度队列里找到需要接收广播的广播接收者,并且将广播发送到广播接收者所运行的应用程序进程。

(4)广播接收者运行的应用程序进程接收到AMS发送过来的广播后,并不是直接处理,而是将广播封装成一个消息发送到主线程的消息队列中。当等到这个消息被处理时,应用程序进程再处理。

图3 广播的发送处理过程(1-4)

(1)CounterService.startCounter

package/experimental/Broadcounter/.../CounterService.java

public class CounterService extends Service implements ICounterService {public void startCounter(int initVal) {AsyncTask<Integer, Integer, Integer> task = new AsyncTask<>() {......@Overrideprotected void onProgressUpdate(Integer... values) {super.onProgressUpdate(values);int counter = values[0];Intent intent = new Intent(BROADCAST_COUNTER_ACTION);intent.putExtra(COUNTER_VALUE, counter);sendBroadcast(intent);}@Overrideprotected void onPostExecute(Integer val) {int counter = val;Intent intent = new Intent(BROADCAST_COUNTER_ACTION));intent.putExtra(COUNTER_VALUE, counter);sendBroadcast(intent);}};task.execute(initVal);}......}

异步任务AsyncTask

(2)ContextWrapper.sendBroadcast

frameworks/base/core/java/android/content/ContextWrapper.java

public class ContextWrapper extends Context {Context mBase;......@Overridepublic void sendBroadcast(Intent intent) {mBase.sendBroadcast(intent);}}

mBase指向ContextImpl对象。

(3)ContextImpl.sendBroadcast

frameworks/base/core/java/android/app/ContextImpl.java

class ContextImpl extends Context {......@Overridepublic void sendBroadcast(Intent intent) {String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());try {ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(), intent, resolvedType, null,Activity.RESULT_OK, null, null, null, false ,false);} catch (RemoteException e) {}}}

AMS的代理对象类型ActivityManagerProxy。

(4)ActivityManagerProxy.broadcastIntent

frameworks/base/core/java/android/app/ActivityManagerNative.java

class ActivityManagerProxy implements IActivityManager {public int broadcastIntent(IApplicationThread caller,Intent intent, String resolvedType, IIntentReceiver resultTo,int resultCode, String resultData, Bundle map,String requiredPermission, boolean serialized, boolean sticky) throws RemoteException{Parcel data = Parcel.obtain();Parcel reply = Parcel.obtain();data.writeInterfaceToken(IActivityManager.descriptor);data.writeStrongBinder(caller != null ? caller.asBinder() : null);intent.writeToParcel(data, 0);data.writeString(resolvedType);data.writeStrongBinder(resultTo != null ? resultTo.asBinder() : null);...mRemote.transact(BROADCAST_INTENT_TRANSACTION, data, reply, 0);...}}

向AMS发送一个BROADCAST_INTENT_TRANSACTION的进程间通信请求,以上(1)~(4)是在应用程序Broadcounter中执行的,(5)~(12)是在AMS中执行的。

图4 广播的发送处理过程(5-12)

(5)ActivityManagerService.broadcastIntent

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {public final int broadcastIntent(IApplicationThread caller,Intent intent, String resolvedType, IIntentReceiver resultTo,int resultCode, String resultData, Bundle map,String requiredPermission, boolean serialized, boolean sticky) {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,map, requiredPermission, serialized, sticky, callingPid, callingUid);Binder.restoreCallingIdentity(origId);return res;}}}

verifyBroadcastLocked用来校验广播是否合法。在系统的启动过程中PMS可能还未被启动,这种情况下AMS是无法获得静态注册的广播接收者的,应该禁止发送广播给静态注册的广播接收者。

(6)ActivityManagerService.broadcastIntentLocked

这一步是用来查找目标广播接收者的,分段阅读。

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

public final class ActivityManagerService extends ActivityManagerNativeimplements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {public final int broadcastIntentLocked(ProcessRecord callerApp,String callerPackage, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle map, String requiredPermission, boolean ordered, boolean sticky, int callingPid, int callingUid){intent = new Intent(intent);...// Add to the sticky list if requestedif (sticky) {...ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());if (list == nullptr) {list = new ArrayList<Intent>();mStickyBroadcasts.put(intent.getAction(), list);}int N = list.size();int i;for (i=0;i<N;i++) {// 如果存在if (intent.filterEquals(list.get(i))) {// This sticky already exists, replace itlist.set(i, new Intent(intent));break;}}// 如果不存在if (i>=N) {list.add(new Intent(intent));}} ...

AMS中,所有相同类型的黏性广播都保存在一个列表(mStickyBroadcasts)中。mStickyBroadcasts是个HashMap,关键字为广播类型(intent.getAction())。

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

// Figure out who all will receive this broadcast.List receivers = null;List<BroadcastFilter> registerReceivers = null;try {if (intent.getComponent() != null) {// Broadcast is going to one specific receiver class...ActivityInfo ai = AppGlobals.getPackageManager().getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);if (ai != null) {receivers = new ArrayList();ResolveInfo ri = new ResolveInfo();ri.activityInfo = ai;receivers.add(ri);}} else {// Need to resolve the intent to interested receivers...if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {receivers = AppGlobals.getPackageManager().queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS);}registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);}} catch (RemoteException ex) {...}...

如果intent指定了广播接收者的组件名称(intent.getComponent()),就说明广播要发送给特定的广播接收者。通过getReceiverInfo()根据intent组件类型在PMS中找到对应的广播接收者,将广播接收者保存在列表receivers里。

如果intent没有指定广播接收者的组件名称,就说明广播是要发送给所有注册的,并且要接收它的广播接收者的。这些目标广播接收者分为两类:

(1)静态注册的

intent的标志位FLAG_RECEIVER_REGISTERED_ONLY为0,为静态注册的广播接收者,保存在列表receivers。

(2)动态注册的

动态注册的广播接收者保存在AMS类的成员变量mReceiverResolver中,保存在registeredReceivers。

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

final boolean replacePending = (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0; int NR = registeredReceivers != null ? registeredReceivers.size() : 0;if (!ordered && NR > 0) {// If we are not serializing this broadcast, then send the registed receivers separately so they don't wait for the components to be launchedBroadcastRecord r = new BroadcastRecord(intent, callerApp, callerPackage, callingPid, callingUid, requiredPermission, registeredReceivers, resultTo, resultCode, resultData, map, ordered, sticky, false);...boolean replaced = false;if (replacePending) {for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {...mParallelBroadcasts.set(i, r);replaced = true;break;}}}if (!replaced) {mParallelBroadcasts.add(r);scheduleBroadcastsLocked();}registeredReceivers = null;NR = 0;}

可能会出现这样一种情况:上次接收的广播还没来得及转发给目标广播接收者,又收到了一个同样的广播。这种情况下,如果广播的标志位FLAG_RECEIVER_REPLACE_PENDING为1,那么AMS会使用新的广播来替代旧的广播。

!ordered表示无序广播,NR>0表示存在动态注册的目标广播接收者。

广播转发任务不是立即执行的,而是被添加到AMS的一个无序广播调度队列中等待执行的。(mParallelBroadcasts)

replaced为true表示不需要在AMS的无序广播调度队列里新增广播转发任务;否则,会将BroadcastRecord描述的广播转发任务添加到AMS的无序广播调度队列里,调用scheduleBroadcastsLocked来重新调度队列中的广播转发任务。

截至目前,对于无序广播,AMS已经将广播转发给动态注册的目标广播接收者了。

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

// Merge into one list int ir = 0;if (receivers != null) {...int NT = receivers != null ? receivers.size() : 0;int it = 0;ResolveInfo curt = null;BroadcastFilter curr = null;while (it < NT && ir < NR) {if (curt == null) {// 静态注册curt = (ResolveInfo)receivers.get(it);}if (curr == null) {// 动态注册curr = registeredReceivers.get(ir);}if (curr.getPriority() >= curt.priority) {// Insert this broadcast record into the final listreceivers.add(it, curr);ir++;curr = null;it++;NT++; } else {// Skip to the next ResolveInfo in the final listit++;curt = null;}}} while (ir < NR) {if (receivers == null) {receivers = new ArrayList();}receivers.add(registeredReceivers.get(ir));ir++; }

AMS内部用mOrderedBroadcasts来描述一个有序广播调度队列,队列中的每个目标广播接收者都是按照优先级从高到低的顺序来排列,不论是动态注册还是静态注册的。

while循环用来合并动态注册和静态注册的目标广播接收者。合并后的目标广播接收者都保存在列表receivers,它们是按照优先级从高到低的顺序来排列的。

合并之前,保存在registeredReceivers和receivers两个列表中的目标广播接收者都是按照优先级从高到低的顺序排列的。合并后,目标广播接收者仍然按照优先级从高到低的顺序排列在receivers中。

函数执行到这里,无论AMS当前接收到的是一个无序广播,还是有序广播,AMS都会将广播和目标广播接收者封装成一个广播转发任务,并且添加到有序广播调度队列里。只是对于无序广播,当它们真正被转发时,不按照有序广播的方式转发罢了。

截至目前,对于无序广播,静态注册的目标广播接收者保存在receivers了(动态注册的目标广播接收者在registeredReceivers,已经添加到无序广播调度队列里了);对于有序广播,静态注册和动态注册的目标广播接收者都保存在receivers了。

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

if ((receivers != null && receivers.size() > 0) || resultTo != null) {BroadcastRecord r = new BroadcastRecord(intent, callerApp, callerPackage, callingPid, callingUid, requiredPermission,receivers, resultTo, resultCode, resultData, map, ordered, sticky, false);...boolean replaced = false;if (replacePending) {for (int i=mOrderedBroadcasts.size()-1; i>0; i--) {if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {...mOrderedBroadcasts.set(i, r);replaced = true;break;}}}if (!replaced) {mOrderedBroadcasts.add(r);scheduleBroadcastsLocked();}return BROADCAST_SUCCESS;}...}

将intent描述的广播和之前receivers描述的目标广播接收者封装为BroadcastRecord对象r,添加到AMS内部的有序广播调度队列中。

如果replaced为true,说明不需要在AMS的有序广播调度队列中增加新的广播转发任务,就不需要再去调度队列中的广播转发任务。

至此,AMS就找到了广播所描述的目标广播接收者了,分别将它们保存在无序广播调度队列mParallelBroadcasts和有序广播调度队列mOrderedBroadcasts()中。接下来,AMS调用scheduleBroadcastLocked函数将广播转发给目标广播接收者。

总结:

mParallelBroadcasts中存放的是动态注册的无序广播,registeredReceivers。

mOrderedBroadcasts中存放的是静态注册和动态注册的有序广播+静态注册的无序广播,receivers。

(7)ActivityManagerService.scheduleBroadcastLocked

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

public final class ActivityManagerService extends ActivityManagerNativeimplements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {...private final void schedualBroadcastsLocked() {if (mBroadcastsScheduled) {return;} mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);mBroadcastsScheduled = true;}}

mBroadcastsScheduled用来描述AMS是否已经向它所在的线程的消息队列发送了一个类型为BROADCAST_INTENT_MSG的消息。

BROADCAST_INTENT_MSG消息最后是在AMS的成员变量mHandler成员函数handleMessage。

(8)Handler.handle Message

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

public final class ActivityManagerService extends ActivityManagerNativeimplements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {...final Handler mHandler = new Handler() {public void handleMessage(Message msg) {switch (msg.what) {...case BROADCAST_INTENT_MSG: {...processNextBroadcast(true);} break;...}}}}

(9)ActivityManagerService.processNextBroadcast

用来将广播转发给目标广播接收者处理,分段阅读。

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

public final class ActivityManagerService extends ActivityManagerNativeimplements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {...private final void processNextBroadcast(boolean fromMsg) {synchronized(this) {BroadcastRecord r;...if (fromMsg) {mBroadcastsScheduled = false;}// First, deliver any non-serialized broadcasts right awaywhile (mParallelBroadcasts.size() > 0) {r = mParallelBroadcasts.remove(0);...final int N = r.receivers.size();...for (int i=0; i<N; i++) {Object target = r.receivers.get(i);...deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);}...}

fromMsg为true,将mBroadcastsScheduled置为false。表示前面发送到AMS运行线程的消息队列中的BROADCAST_INTENT_MSG消息已经被处理了。

如上处理无序广播调度队列。下面处理有序广播调度队列:

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

// if we are waiting for a process to come up to handle the next broadcast, then do nothing at this point.// Just in case, we check that the process we're waiting for still exists.if (mPendingBroadcast != null) {...boolean isDead;synchronized (mPidsSelfLocked) {isDead = mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null;}if (!isDead) {// it's stll alive, so keep waitingreturn;} else {...mPendingBroadcast.state = BroadcastRecord.IDLE;mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;mPendingBroadcast = null;}}

有序广播调度队列mOrderBroadcast的目标广播接收者可能是静态注册的,这些广播接收者可能还没有启动起来。

mPendingBroadcast用来描述一个正在等待静态注册的目标广播接收者的广播的。如果存在这样的广播,会先检查应用程序是否已经启动。

如果应用程序正在启动,AMS会继续等待;如果应用程序没有启动,AMS会向应用程序发送一个广播,应用程序收到AMS发送的广播后,会主动将目标广播接收者启动起来。

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

do {if (mOrderedBroadcasts.size() == 0) {...return;}r = mOrderedBroadcasts.get(0);boolean forceReceive = false;...int numReiceivers = (r.receivers != null) ? r.receivers.size() : 0;if (mProcessReady && r.dispatchTime > 0) {long now = SystemClock.uptimeMillis();if ((numReceivers > 0) && (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {...// forcibly finish this broadcastbroadcastTimeoutLocked(false);forceReceive = true;r.state = BroadcastRecord.IDLE;}}// 检查r描述的广播转发任务是否正在处理中if (r.state != BroadcastRecord.IDLE) {...return;}// 检查r描述的广播转发任务是否已经完成或已经被强制结束if (r.receivers == null || r.nextReceiver >= numReceivers || r.resultAbort || forceReceive) {//No more receivers for this broadcast! Send the final result if requested......cancelBroadcastTimeoutLocked();...// ... and on to the next ......mOrderedBroadcasts.remove(0);r = null;...continue;}} while (r == null);

先检查目标广播接收者是否在规定的时间内处理完AMS给它发送的一个有序广播。如果超时,调用broadcastTimeoutLocked来强制结束这个广播任务。

循环跳出后,下一个需要处理的广播转发任务就保存在r中了。

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

// Get the next receiver...int recIdx = r.nextReceiver++;// Keep track of when this receiver started, and make sure there is a timeout message pending to kill it if need be.r.receiverTime = Systemclock.uptimeMillis();if (recIdx == 0) {r.dispatchTime = r.receiverTime;...}// 检查AMS是否已经向它所运行的线程的消息队列发送了类型为BROADCAST_TIMEOUT_MSG的消息if (!mPendingBroadcastTimeoutMessage) {long timeoutTime = r.receiverTime + BROADCAST_TIMEOUT;setBroadcastTimeoutLocked(timeoutTime);} Object nextReceiver = r.receivers.get(recIdx);if (nextReceiver instanceof BroadcastFilter) {// Simple case: this is a registered receiver who gets a direct call.BroadcastFilter filter = (BroadcastFilter)nextReceiver;....deliverToRegisteredReceiverLocked(r, filter, r.ordered);// 检查r所描述的广播转发任务是否是用来转发无序广播的或广播已经处理完成if (r.receiver == null || !r.ordered) {// The receiver has already finished, so schedule to process the next one...// 因为是无序广播或已经处理完的广播,所以AMS不需要等待它的前一个广播处理完成就可以将该广播发送给它的下一个目标r.state = BroadcastRecord.IDLE;scheduleBroadcastLocked();} return;}

由(6)可知,如果下一个目标广播接收者nextReceiver的类型为BroadFilter,那么就说明它是一个动态注册的广播接收者。那么就可以直接调用deliverToRegisteredReceiverLocked发送一个广播,因为动态注册的广播接收者一定是已经启动的。

如果下一个目标广播接收者nextReceiver的类型不是BroadFilter,就说明这是一个静态注册的广播接收者(ResolveInfo)。这种情况较为复杂,因为静态注册的广播接收者可能还没有启动。

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

// Hard case: need to instantiate the receiver, possibly starting its application process to host it.ResolveInfo info = (ResolveInfo)nextReceiver;...String targetProcess = info.activityInfo.processName;...// Is this receiver's application already running?ProcessRecord app = getProcessRecordLocked(targetProcess, info.activityInfo.applicationInfo.uid);if (app != null && app.thread != null) {try { processCurBoardcastLocked(r, app);return;} catch (RemoteException e) {...}...}// Not running -- get it started, to be executed when the app come up.if ((r.curApp = startProcessLocked(...)) == null) {// this recipient(接收者) is unavaiable. Finish it if necessary, and mark the broad cast record as ready fot the next....scheduleBroadcastLocked();r.state = BroadcastRecord.IDLE;return;} mPendingBroadcast = r;mPendingBroadcastRecnIndex = recIdx;}}...}

如果应用程序已经启动,调用processCurBoardcastLocked将广播发送给它处理;启动失败,调用scheduleBroadcastLocked来结束对广播r的转发任务的处理。将r和recIdx保存在mPendingBroadcast和mPendingBroadcastRecnIndex中,表示AMS正在等待r所描述的广播转发任务的下一个目标广播接收者所在的应用程序进程启动起来。

假设r所描述的广播转发任务的下一个目标接收者是一个动态注册的广播接收者,或是一个静态注册的已经启动的广播接收者,下一步会调用deliverToRegisteredReceiverLocked来转发广播。

(10)AcitvityManagerService.deliverToRegisteredReceiverLocked

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

public final class ActivityManagerService extends ActivityManagerNativeimplements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {...private final void deliverToRegisteredReceiverLocked(BroadcastRecord r, BroadcastFilter filter, boolean ordered) {boolean skip = false;// 发送者权限if (filter.requiredPermission != null) {int perm = checkComponentPermission(filter.requiredPermission, r.callingPid, r.callingUid, -1);if (perm != PackageManager.PERMISSION_GRANTED) {...skip = true;}}// 接收者权限if (r.requiredPermission != null) {int perm = checkComponentPermission(r.requiredPermission, filter.receiverList.pid, filter.receiverList.uid, -1);if (perm != PackageManager.PERMISSION_GRANTED) {...skip = true;}} if (!skip) {...try {performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver, new Intent(r.intent), r.resultCode, r.resultData, r.resultExtras, r.ordered, r.initialSticky);} catch (RemoteException e) {...}}}}

需要检查广播发送者和接收者的权限。检查是双向的,即检查发送者是否有权限向接收者发送广播,检查接收者是否有权限接收来自发送者的广播。

(11)AcitvityManagerService.performReceiveLocked

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

public final class ActivityManagerService extends ActivityManagerNativeimplements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {...static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver, Intent intent,int resultCode, String data, Bundle extras, boolean ordered, boolean sticky) throws RemoteException {// Send the intent to the receiver asynchronously using one-way binder callsif (app != null && app.thread != null) {// if we have an app thread, do the call through that so it is correctly ordered with other one-way callsapp.thread.scheduleRegisteredReceiver(receiver, intent, resultCode, data, extras, ordered, sticky);} else {receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);} }}

app描述目标广播接收者所运行的应用程序进程;receiver实现了IIntentReceiver接口的Binder代理对象,描述目标广播接收者;intent用来描述要发送给目标广播接收者的广播。

如果目标广播接收者需要通过它所运行的应用程序进程来接收一个广播,那么会调用运行在应用程序进程中的ApplicationThread对象的Binder代理对象的成员函数scheduleRegisteredReceiver来向它发送这个广播;否则,直接调用IntentReceiver对象的Binder代理对象的成员函数perfromReceive来向它发送这个广播。

假设app.thread != null,app描述的应用进程即为Broadcounter所运行的进程,app.thread为Broadcounter进程的一个ApplicationThread对象的Binder代理对象,即ApplicationThreadProxy对象。

(12)ApplicationThreadProxy.scheduleRegisteredReceiver

frameworks/base/core/java/android/app/ApplicationThreadNative.java

class ApplicationThreadProxy implements IApplicationThread {...public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent, int resultCode,String dataStr, Bundle extras, boolean ordered, boolean sticky) throws RemoteException {Parcel data = Parcel.obtain();data.writeInterfaceToken(IApplicationThread.descriptor);data.writeStrongBinder(receiver.asBinder());intent.writeToParcel(data, 0);data.writeInt(resultCode);data.writeString(dataStr);data.writeBundle(extras);data.writeInt(ordered?1:0);data.writeInt(sticky?1:0);mRemote.transact(SCHEDULE_REGISTERED_RECEIVER_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);data.recycle();} }

IBinder.FLAG_ONEWAY表示进程间通信是异步的。

以上8步是在AMS进程中执行的,下面13-17步是在应用程序Broadcounter进程中执行的,用来处理AMS发出的SCHEDULE_REGISTERED_RECEIVER_TRANSACTION的进程间通信请求。

图5 广播的发送处理过程(13-17)

(13)ApplicationThread.scheduleRegisteredReceiver

frameworks/base/core/java/android/app/ActivityThread.java

public final class ActivityThread {...private final class ApplicationThread extends ApplicationThreadNative {...public void schedualRegisteredReceiver(IIntentReceiver receiver, Intent intent, int resultCodeString dataStr, Bundle extras, boolean ordered, boolean sticky) throws RemoteException {receiver.performReceive(intent, resultCode, dataStr, extras, ordered, sticky);}}}

(14)InnerReceiver.performReceive

frameworks/base/core/java/android/app/LoadedApk.java

final class LoadedApk {...static final class ReceiverDispatcher {final static class InnerReceiver extends IIntentReceiver.Stub {final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;...public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky) {LoadedApk.ReceiverDispacher rd = mDispatcher.get();...if (rd != null) {rd.performReceive(intent, resultCode, data, extras, ordered, sticky);}}}}}

mDispatcher是ReceiverDispacher的弱引用,rd.performReceive实际上是调用ReceiverDispatcher的performReceive函数来接收intent描述的广播。

(15)ReceiverDispatcher.performReceive

frameworks/base/core/java/android/app/LoadedApk.java

final class LoadedApk {...static final class ReceiverDispatcher {...final Handler mActivityThread;...public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky) {...Args args = new Args();args.mCurIntent = intent;args.mCurCode = resultCode;args.mCurData = data;args.mCurMap = extras;args.mCurOrdered = ordered;args.mCurSticky = sticky;if (!mActivityThread.post(args)) {...}}...}}

mActivityThread Handler对象指向ActivityThread类的成员变量mH,用来向Broadcounter的主线程的消息队列发送消息。将intent封装成一个Args对象,发送到Broadcounter的主线程的消息队列中。这个消息是在Args类的run函数中处理的。

(16)Args.run

frameworks/base/core/java/android/app/LoadedApk.java

final class LoadedApk {...static final class ReceiverDispatcher {...final BroadcastReceiver mReceiver;final boolean mCurOrderred;...public void run() {BroadcastReceiver receiver = mReceiver;...IActivityManager mgr = ActivityManagerNative.getDefault();Intent intent = mCurIntent;...try {receiver.onReceive(mContext, intent);} catch (Exception e) {...}if (mRegistered && mCurOrdered) {try {mgr.finishReceiver(mIIntentReceiver, receiver.getResultCode(), receiver.getResultData(), receiver.getResultExtras(false), receiver.getAbortBroadcast());} catch (RemoteException e) {...}}}}}

mRegistered用来描述mReceiver指向的广播接收者是否已经注册到AMS。mCurOrdered表示是否是一个有序广播。

如果广播接收者是否已经注册到AMS且是一个有序广播,需要调用AMS代理对象mgr的成员函数finishReceiver来通知AMS,它前面转发出来的有序广播已经处理完了。这时,AMS可以继续将这个有序广播转发给下一个目标广播接收者处理。

(17)BroadcastReceiver.onReceive

/package/experimental/Broadcounter/xxx/Broadcounter.java

public class Broadcounter extends Activity implements OnClickListener {...private BroadcastReceiver counterActionReceiver = new BroadcastReceiver() {public void onReceive(Context context, Intent intent) {int counter = intent.getIntExtra(CounterService.COUNTER_VALUE, 0);String text = String.valueof(counter);counterText.setText(text);}}}

intent用来描述广播。context用来描述将广播接收者注册到AMS中的Activity组件或Service组件。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。