http://blog.csdn.net/hehui1860/article/details/30726609
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中处理的过程了,将在后续篇章中进行阐述。