导读:本文说明系统是如何注册动态广播以及静态广播,这里主要注意其注册的顺序
这篇文章主要是针对我前两篇文章
之前只给出了结果,并没有给出代码分析,现在给出第一步分的分析
大家都知道,广播接收器分为动态注册和静态注册两种
静态接收,就是配置到manifest.xml文件中,PackageManagerService扫描后记录其信息……
动态接收,就是从代码中注册,通过调用下面的方法实现
Intent android.content.Context.registerReceiver(BroadcastReceiver receiver, IntentFilter filter)
(下面的流程图估计画的比较水,将就看一下吧,得补习一下UML了)
首先分析静态注册Receiver的流程
静态receiver的注册是由PackageManagerService开机的时候负责初始化
(PackageManagerService之后简称为PMS)
PMS在开机的时候会对系统一些目录逐个扫描,解析apk文件。静态广播接收器就是在PMS做这件事情的时候顺便处理的。
PMS会解析apk的manifest文件,查找这里注册的receiver,然后加载到内存中
下面看一下PMS是如何工作的
这部分内容没有什么难度,只要有耐心就行,我画了一个很简单流程图,从调用PMS的构造函数开始
注意,这里有几个同名函数,大家需要分清。并不是同一个函数调用了两次
这里只看几处
1.PMS初始化的时候干了些什么
当然,PMS会做很多很多事情,这里我们只看我们关注的,和这篇文章相关的部分
// Collect all system packages. 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);
扫描目录的顺序
system/framework
system/app
vendor/app
data/app
drm/app-private
这里以system/app目录为例
2.下一个要关注的地方是
void com.android.server.pm.PackageManagerService.scanDirLI(File dir, int flags, int scanMode, long currentTime)
private void scanDirLI(File dir, int flags, int scanMode, long currentTime { String[] files = dir.list(); …… int i; for (i=0; i<files.length; i++) { File file = new File(dir, files[i]); …… PackageParser.Package pkg = scanPackageLI(file, flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime); …… } }
注意
String[] files = dir.list();
以及之后的for循环
3.之后的部分比较无聊,我们直接跳到parseApplication函数部分
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); }
这部分就是解析manifest中的receiver部分,大家会很奇怪,receiver为什么会变成一个Activity
此Activity非彼Activity,这个Activity是PackageParser的一个内部类,结构也非常简单
public final static class Activity extends Component<ActivityIntentInfo> { public final ActivityInfo info; public Activity(final ParseComponentArgs args, final ActivityInfo _info) { super(args, _info); info = _info; info.applicationInfo = args.owner.applicationInfo; } public void setPackageName(String packageName) { super.setPackageName(packageName); info.packageName = packageName; } …… }
我们看到了PMS如何在初始化的时候如何解析manifest并把其中的element存放到内存中的
其中receiver保存到了owner的成员变量receivers中,owner的类型是android.content.pm.PackageParser.Package
也就是说,在上面的#2步中,scanPackageLI返回结果就是已经包含了manifest信息的Package对象
4.现在还没有结束,返回的结果最终交给了谁,我们还没有看到,在下面的这个函数中,我们终于发现了端倪
Package com.android.server.pm.PackageManagerService.scanPackageLI(Package pkg, int parseFlags, int scanMode, long currentTime)
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"); …… }
原来,最终是添加到了PMS中的成员变量mReceivers中
// All available receivers, for your resolving pleasure. final ActivityIntentResolver mReceivers = new ActivityIntentResolver();、
下面我们看看它是如何add的
void com.android.server.pm.PackageManagerService.ActivityIntentResolver.addActivity(Activity a, String type)
void com.android.server.IntentResolver.addFilter(ActivityIntentInfo f)
public void addFilter(F f) { ...... mFilters.add(f); int numS = register_intent_filter(f, f.schemesIterator(), mSchemeToFilter, " Scheme: "); int numT = register_mime_types(f, " Type: "); //根据我下面红色文字的假设,这里numS和numT应该都为0 if (numS == 0 && numT == 0) { register_intent_filter(f, f.actionsIterator(), mActionToFilter, " Action: "); } if (numT != 0) { register_intent_filter(f, f.actionsIterator(), mTypedActionToFilter, " TypedAction: "); } }
由于开机启动和接收短信并不涉及MIME Type、Scheme等因素。所有我们只考虑Intent中的Action,MIME Type、Scheme等均不考虑
最后看一下register_intent_filter函数,里面没有任何关于排序的代码,只是按顺序add到list中
private final int register_intent_filter(F filter, Iterator<String> i, HashMap<String, ArrayList<F>> dest, String prefix) { if (i == null) { return 0; } int num = 0; while (i.hasNext()) { String name = i.next(); num++; if (localLOGV) Slog.v(TAG, prefix + name); ArrayList<F> array = dest.get(name); if (array == null) { //Slog.v(TAG, "Creating new array for " + name); array = new ArrayList<F>(); dest.put(name, array); } array.add(filter); } return num; }
Action保存在mActionToFilter中记录,之后发送广播的时候,查找接收器还要靠mActionToFilter这个成员变量
每个action对应一个List,含有此action的filter将被保存到同一个List中
我们要注意一个事情,那就是mReceivers保存这些receiver的顺序
那就是一直与#2步的顺序保持一致,没有遭到破坏
甚至并没有根据优先级排序,只是一味的add
---------------------------------------------------------------
静态广播接收器的注册分析完了,之后就是系统发出广播,然后如何去分发给他们了
我们下篇文章再来分析
下面看看动态接收器的注册流程
我们也是画个简单的流程图,只看关键代码
最终会调用到AMS中的registerReceiver函数
其中关键部分如下
ReceiverList rl = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder()); if (rl == null) { rl = new ReceiverList(this, callerApp, Binder.getCallingPid(), Binder.getCallingUid(), 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); } BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission); rl.add(bf); if (!bf.debugCheck()) { Slog.w(TAG, "==> For Dynamic broadast"); } mReceiverResolver.addFilter(bf);
mReceiverResolver的类型为IntentResolver<BroadcastFilter, BroadcastFilter>
mReceiverResolver.addFilter(bf);
在上面已经简述过了
最终所有动态注册的receiver都保存到AMS的成员变量mReceiverResolver中
/** * Resolver for broadcast intents to registered receivers. * Holds BroadcastFilter (subclass of IntentFilter). */ final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver = new IntentResolver<BroadcastFilter, BroadcastFilter>() { @Override protected boolean allowFilterResult(BroadcastFilter filter, List<BroadcastFilter> dest) { IBinder target = filter.receiverList.receiver.asBinder(); for (int i=dest.size()-1; i>=0; i--) { if (dest.get(i).receiverList.receiver.asBinder() == target) { return false; } } return true; } @Override protected String packageForFilter(BroadcastFilter filter) { return filter.packageName; } };
总结:
静态广播和动态广播如何注册的,我们已经全部分析完了
静态广播是PackageManagerService负责,保存到其成员变量mReceivers中
动态广播是ActivityManagerService负责,保存到其成员变量mReceiverResolver中
注册的顺序:
动态广播与应用中调用的顺序一致
静态广播参考函数
void com.android.server.pm.PackageManagerService.scanDirLI(File dir, int flags, int scanMode, long currentTime)
注意
String[] files = dir.list();
以及之后的for循环
由于开机启动和接收短信并不涉及MIME Type、Scheme等因素。所有我们这里只考虑Intent中的Action,MIME Type、Scheme等均不考虑
保存的顺序参考函数
void com.android.server.IntentResolver.addFilter(ActivityIntentInfo f)
int com.android.server.IntentResolver.register_intent_filter(F filter, Iterator<String> i, HashMap<String, ArrayList<F>> dest, String prefix)
下篇文章将讲述发送广播之后,系统如何查找对应的receiver。在这个过程中,系统才开始考虑优先级。
下篇文章顺便看看隐式Intent是如何查找到目标组件的
转贴请保留以下链接
本人blog地址
相关推荐
- 港区内因生产需要使用炉火时,需由单位消防安全责任人审批,并报辖区派出所备案。 - 港区内临时建筑严禁使用各种明火炉具。 - 施工工地需要使用明火炉具的食堂,需经建设主管部门的消防安全责任人审批,并报辖区...
- **重要性**:耐用性是评估接收机质量的重要指标之一,尤其在1990年后成为了关键考量因素。 ##### 3. 动态性能 - **指标**:动态性能的指标对于不同的应用场景有所不同。例如,陆用和海用接收机至少需要支持2g的...
- **输入**:流程开始时所接收的信息或材料。 - **输出**:流程结束时产生的结果或产品。 - **相互关系**:指流程中各个步骤之间的相互依赖和协作。 - **SIPOC**:提供了一个宏观视角来审视流程,并强调了供应商与...
PHA方法的运用,不仅能够提前发现和消除安全隐患,还能指导完善安全规章制度,优化作业流程,从而有效预防矿井内因火灾。此外,PHA的结果可以作为矿井安全管理决策的科学依据,促进安全管理体系的持续改进。 总的来...
为了矿井内因火灾防治工作更好更快的发展,结合矿井内因火灾形成机理,详细全面地介绍了开采技术措施、堵漏、均压、注浆、惰性气体、阻化剂、凝胶及三相泡沫防灭火技术进行矿井内因火灾防治的原理、技术材料及其工艺...
- 详述了在三包期内因质量问题导致换货时的价格差额处理流程。 以上是对某集团业务流程案例中的主要知识点进行的详细解析。这些流程不仅为内部管理提供了明确的指导,也为外部审计或评估提供了有力的支持。通过...
2022年下半年福建省安全工程师安全生产法:内因火灾的预防方法考试题定义.pdf
煤矿内因火灾影响着煤矿的安全高效生产,目前煤矿内因火灾评价准确度较低,评价方法过于陈旧。针对此问题,提出一种基于集对分析-区间三角模糊数的煤矿内因火灾危险性评价耦合模型,集对分析多元联系数可以兼顾煤矿内因...
【标题】:“大斗沟井下外因内因火灾事故应急救援预案”是针对矿井火灾安全防范的重要文档,旨在确保在发生此类事故时能够迅速、有效地实施救援行动,保护人员安全并减小财产损失。 【描述】:该文档作为专题资料,...
信息安全问题的根源可以分为内因和外因。内因通常源于信息系统的复杂性,导致漏洞不可避免;外因则包括环境因素和人为因素,如黑客攻击、恶意软件等。信息安全的特性包括系统性、动态性、无边界和非传统,意味着安全...
### IT与安全生产技术知识点解析 #### 一、安全生产事故分类 - **责任事故与非责任事故**: 生产安全事故可以分为责任事故和非责任事故两大类。责任事故是指由于人为因素如管理不善、操作失误等原因导致的事故;而...
4. **软件开发方法存在问题**:不合理的开发流程、缺少安全测试等都会导致软件出现安全问题。 **外因**:主要指的是软件运行过程中面临的外部威胁。 1. **网络对软件的影响**:互联网的发展使得软件更容易受到来自...
- **CISP**:注册信息安全专业人员(Certified Information Security Professional)是信息安全领域的重要认证之一。 - **课程内容**:涵盖信息安全保障、信息安全工程、信息安全法规政策和标准、信息安全管理等多个...
从作用因素来看,安全生产保证体系可以理解为内因,它直接影响到企业的安全文化、安全意识和安全管理的规范性,是企业内在的安全防护屏障。而安全监督体系则扮演着外因的角色,它通过外部的约束力和检查机制,促使...
软件安全问题产生-内因软件规模增大,功能越来越多,越来越复杂;软件模块复用,导致安全漏洞延续;软件扩展模块带来的安全问题Windows操作系统不同版本源代码数量。 软件安全问题产生-外因互联网发展对软件安全的...
第1章“轨道交通大发 展的时代”与第2章“轨道交通车辆的安全问题”与 城轨交通的发展 历史和当前形势接轨,搜集、调查了国际国内的若干 素材。在第3章,介绍了轨道车辆走行部常见故障。第4章 “轨道车辆走行部检测...