Android系统的广播机制应用非常的广泛,是一种方便快捷的进程间通信的方式。同时它也有一些很有特殊的使用方式,比如它的两种注册方式,三种类型的广播等,这些充斥在整个系统框架中,那么为了用好广播,很有必要对其源码进行分析,从而避免一些低级失误。
本文将对整个广播机制涉及到的知识做个粗略的讲解,为大家自学抛砖引玉。
首先我们从注册当时入手,牵引出与本机制有关的一些类:Packagemanager
在系统服务启动时添加PackageManagerService,在这个过程中packagemanager就会对各个app安装目录的apk文件进行扫描解析。
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
……
mSystemAppDir = new File(Environment.getRootDirectory(), "app");
mSystemInstallObserver = new AppDirObserver(
mSystemAppDir.getPath(), OBSERVER_EVENTS, true);
mSystemInstallObserver.startWatching();
scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
//后续还有其他路径下的app文件扫描
……
}
private void scanDirLI(File dir, int flags, int scanMode, long currentTime) {
……
for (i=0; i<files.length; i ) {
PackageParser.Package pkg = scanPackageLI(file,
flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime, null);
……
}
}
private PackageParser.Package scanPackageLI(File scanFile,
int parseFlags, int scanMode, long currentTime, UserHandle user) {
PackageParser pp = new PackageParser(scanPath);
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
final PackageParser.Package pkg = pp.parsePackage(scanFile,
scanPath, mMetrics, parseFlags);
…….
PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode
| SCAN_UPDATE_SIGNATURE, currentTime, user);
……
}
public Package parsePackage(File sourceFile, String destCodePath,
DisplayMetrics metrics, int flags) {
try {
// XXXX todo: need to figure out correct configuration.
pkg = parsePackage(res, parser, flags, errorText);
} catch (Exception e) {
errorException = e;
mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
}
}
private Package parsePackage(
Resources res, XmlResourceParser parser, int flags, String[] outError)
throws XmlPullParserException, IOException {
……
String tagName = parser.getName();
if (tagName.equals("activity")) {
Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false,
hardwareAccelerated);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
owner.activities.add(a);
} else if (tagName.equals("receiver")) {
Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true, false);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
owner.receivers.add(a);
}
…….
}
private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
int parseFlags, int scanMode, long currentTime, UserHandle user) {
……
mPackages.put(pkg.applicationInfo.packageName, pkg);
……
N = pkg.receivers.size();
r = null;
for (i=0; i<N; i ) {
PackageParser.Activity a = pkg.receivers.get(i);
a.info.processName = fixProcessName(pkg.applicationInfo.processName,
a.info.processName, pkg.applicationInfo.uid);
mReceivers.addActivity(a, "receiver");
}
}
到这里可以看到系统是如何解析manifest里面注册的广播接收器的,并且最终将所有的接收器保存到了
// All available receivers, for your resolving pleasure.
final ActivityIntentResolver mReceivers = new ActivityIntentResolver();中,请注意这个成员变量,后面会有用的,这里也暗含了一个静态的排序,也就是首先扫描目录的排序,显示system/app后面是其他的,还有一个就是file.list()对目录下apk文件的默认排序。
还有一种动态注册的方式,平常我们使用registerReceiver其实最终是ContextImpl里面的registerReceiverInternal方法来实现的,可以看看:
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;
}
}
看到最后其实还是activitymanager在工作,android的设计就是如此,由service管理各个组件省去了很多的工作。
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
……
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, receivers, null, 0, null, null,
false, true, true, -1);
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
}
……
}
最终将这些动态广播接收器豆浆保存到成员变量mReceiverResolver中(既然这里是一个个add进去的,隐含了一个排序,也就是先注册的动态广播在前),并且注意allsticky这里的判断,这是sticky广播处理的逻辑,粘性广播会停留在service中等待,以便有人注册这则广播消息后能尽快的收到这条广播。
在注册完了之后,广播主要就是发送和处理了。这个过程都是在activitymanagerservice里面进行的。可以看看它的broadcastIntentLocked方法,主要的工作都是这里进行的,尤其注意的是普通广播与有序广播,以及广播的次序等信息。
private 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,
int userId) {
……
// Add to the sticky list if requested.
if (sticky) {
if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
callingPid, callingUid)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
callingPid ", uid=" callingUid
" requires " android.Manifest.permission.BROADCAST_STICKY;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
if (requiredPermission != null) {
Slog.w(TAG, "Can't broadcast sticky intent " intent
" and enforce permission " requiredPermission);
return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;
}
if (intent.getComponent() != null) {
throw new SecurityException(
"Sticky broadcasts can't target a specific component");
}
// We use userId directly here, since the "all" target is maintained
// as a separate set of sticky broadcasts.
if (userId != UserHandle.USER_ALL) {
// But first, if this is not a broadcast to all users, then
// make sure it doesn't conflict with an existing broadcast to
// all users.
HashMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(
UserHandle.USER_ALL);
if (stickies != null) {
ArrayList<Intent> list = stickies.get(intent.getAction());
if (list != null) {
int N = list.size();
int i;
for (i=0; i<N; i ) {
if (intent.filterEquals(list.get(i))) {
throw new IllegalArgumentException(
"Sticky broadcast " intent " for user "
userId " conflicts with existing global broadcast");
}
}
}
}
}
HashMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
if (stickies == null) {
stickies = new HashMap<String, ArrayList<Intent>>();
mStickyBroadcasts.put(userId, stickies);
}
ArrayList<Intent> list = stickies.get(intent.getAction());
if (list == null) {
list = new ArrayList<Intent>();
stickies.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 it.
list.set(i, new Intent(intent));
break;
}
}
if (i >= N) {
list.add(new Intent(intent));
}
}
……
// Figure out who all will receive this broadcast.
//静态广播接收器
List receivers = null;
//动态广播接收器
List<BroadcastFilter> registeredReceivers = null;
// Need to resolve the intent to interested receivers...
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
== 0) {
receivers = collectReceiverComponents(intent, resolvedType, users);
}
if (intent.getComponent() == null) {
registeredReceivers = mReceiverResolver.queryIntent(intent,
resolvedType, false, userId);
}
……
//处理非有序的广播
if (!ordered && NR > 0) {
// If we are not serializing this broadcast, then send the
// registered receivers separately so they don't wait for the
// components to be launched.
final BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, requiredPermission,
registeredReceivers, resultTo, resultCode, resultData, map,
ordered, sticky, false, userId);
if (DEBUG_BROADCAST) Slog.v(
TAG, "Enqueueing parallel broadcast " r);
final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
if (!replaced) {
//只处理了动态注册的接收器
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
registeredReceivers = null;
NR = 0;
}
……
// Merge into one list.
//后面的逻辑就是,如果前面是非有序广播,就先处理与之匹配的动态注册的并置为空,后面的逻辑就只有静态的接收器并处理
//如果前面是有序广播则不处理,此后的逻辑中先对静态和动态的接收器按照priority值进行一个统一的排序最后处理。
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 list.
receivers.add(it, curr);
ir ;
curr = null;
it ;
NT ;
} else {
// Skip to the next ResolveInfo in the final list.
it ;
curt = null;
}
}
}
while (ir < NR) {
if (receivers == null) {
receivers = new ArrayList();
}
receivers.add(registeredReceivers.get(ir));
ir ;
}
if ((receivers != null && receivers.size() > 0)
|| resultTo != null) {
// broadcastQueueForIntent这个方法中对当前是否前台的广播接收器队列进行了判断,前台和后台的接收器处理超时是不一样的,前台是10m,后台是60m。
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, requiredPermission,
receivers, resultTo, resultCode, resultData, map, ordered,
sticky, false, userId);
if (DEBUG_BROADCAST) Slog.v(
TAG, "Enqueueing ordered broadcast " r
": prev had " queue.mOrderedBroadcasts.size());
if (DEBUG_BROADCAST) {
int seq = r.intent.getIntExtra("seq", -1);
Slog.i(TAG, "Enqueueing broadcast " r.intent.getAction() " seq=" seq);
}
boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
if (!replaced) {
queue.enqueueOrderedBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
}
return ActivityManager.BROADCAST_SUCCESS;
}
总结一下这里面含有的排序信息:分为两种,有序广播,首先按照优先级排列,同优先级的动态广播先于静态广播,同优先级的动态广播中先注册的先处理,同优先级的静态广播中先扫描的APP广播先处理。
有序广播则,无视优先级,动态广播先于静态广播,动态广播中先注册的先处理,静态广播中先扫描的APP广播先处理。
以上是广播的注册以及send时候的分发,接下来就是ActivtyManagerService调用到用户程序的broadcastreceiver中处理的过程了,将在后续篇章中进行阐述。
> from eoe.cn