`
su1216
  • 浏览: 670000 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
Group-logo
深入入门正则表达式(jav...
浏览量:71836
E60283d7-4822-3dfb-9de4-f2377e30189c
android手机的安全问...
浏览量:128627
社区版块
存档分类
最新评论

android安全问题(六) 抢先接收广播 - 内因篇之广播接收器注册流程

阅读更多

导读:本文说明系统是如何注册动态广播以及静态广播,这里主要注意其注册的顺序

 

这篇文章主要是针对我前两篇文章

android安全问题(四) 抢先开机启动 - 结果篇

android安全问题(五) 抢先拦截短信 - 结果篇

之前只给出了结果,并没有给出代码分析,现在给出第一步分的分析

 

大家都知道,广播接收器分为动态注册和静态注册两种

静态接收,就是配置到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地址

http://su1216.iteye.com/

http://blog.csdn.net/su1216/

1
0
分享到:
评论

相关推荐

    秦皇岛港使用明火管理规定-安全管理-安全管理制度-消防安全.docx

    - 港区内因生产需要使用炉火时,需由单位消防安全责任人审批,并报辖区派出所备案。 - 港区内临时建筑严禁使用各种明火炉具。 - 施工工地需要使用明火炉具的食堂,需经建设主管部门的消防安全责任人审批,并报辖区...

    GPS接收机性能之分析

    - **重要性**:耐用性是评估接收机质量的重要指标之一,尤其在1990年后成为了关键考量因素。 ##### 3. 动态性能 - **指标**:动态性能的指标对于不同的应用场景有所不同。例如,陆用和海用接收机至少需要支持2g的...

    【流程管理】企业流程体系构建与优化导论-74页.ppt

    - **输入**:流程开始时所接收的信息或材料。 - **输出**:流程结束时产生的结果或产品。 - **相互关系**:指流程中各个步骤之间的相互依赖和协作。 - **SIPOC**:提供了一个宏观视角来审视流程,并强调了供应商与...

    预先危险性分析在矿井内因火灾预防中的应用研究

    PHA方法的运用,不仅能够提前发现和消除安全隐患,还能指导完善安全规章制度,优化作业流程,从而有效预防矿井内因火灾。此外,PHA的结果可以作为矿井安全管理决策的科学依据,促进安全管理体系的持续改进。 总的来...

    我国矿井内因火灾防治技术研究现状

    为了矿井内因火灾防治工作更好更快的发展,结合矿井内因火灾形成机理,详细全面地介绍了开采技术措施、堵漏、均压、注浆、惰性气体、阻化剂、凝胶及三相泡沫防灭火技术进行矿井内因火灾防治的原理、技术材料及其工艺...

    某集团业务流程案例.docx

    - 详述了在三包期内因质量问题导致换货时的价格差额处理流程。 以上是对某集团业务流程案例中的主要知识点进行的详细解析。这些流程不仅为内部管理提供了明确的指导,也为外部审计或评估提供了有力的支持。通过...

    2022年下半年福建省安全工程师安全生产法:内因火灾的预防方法考试题定义.pdf

    2022年下半年福建省安全工程师安全生产法:内因火灾的预防方法考试题定义.pdf

    煤矿内因火灾危险性评价新耦合模型

    煤矿内因火灾影响着煤矿的安全高效生产,目前煤矿内因火灾评价准确度较低,评价方法过于陈旧。针对此问题,提出一种基于集对分析-区间三角模糊数的煤矿内因火灾危险性评价耦合模型,集对分析多元联系数可以兼顾煤矿内因...

    专题资料(2021-2022年)大斗沟井下外因内因火灾事故应急救援预案.doc

    【标题】:“大斗沟井下外因内因火灾事故应急救援预案”是针对矿井火灾安全防范的重要文档,旨在确保在发生此类事故时能够迅速、有效地实施救援行动,保护人员安全并减小财产损失。 【描述】:该文档作为专题资料,...

    CISP信息安全证书培训课件-信息安全保障

    信息安全问题的根源可以分为内因和外因。内因通常源于信息系统的复杂性,导致漏洞不可避免;外因则包括环境因素和人为因素,如黑客攻击、恶意软件等。信息安全的特性包括系统性、动态性、无边界和非传统,意味着安全...

    精品资料(2021-2022年收集)贵州安全工程师《安全生产技术》:砂轮圆周表面考试题.docx

    ### IT与安全生产技术知识点解析 #### 一、安全生产事故分类 - **责任事故与非责任事故**: 生产安全事故可以分为责任事故和非责任事故两大类。责任事故是指由于人为因素如管理不善、操作失误等原因导致的事故;而...

    安全软件开发入门(教程)

    4. **软件开发方法存在问题**:不合理的开发流程、缺少安全测试等都会导致软件出现安全问题。 **外因**:主要指的是软件运行过程中面临的外部威胁。 1. **网络对软件的影响**:互联网的发展使得软件更容易受到来自...

    CISP 培训课程知识总结

    - **CISP**:注册信息安全专业人员(Certified Information Security Professional)是信息安全领域的重要认证之一。 - **课程内容**:涵盖信息安全保障、信息安全工程、信息安全法规政策和标准、信息安全管理等多个...

    软件安全开发V.pptx

    软件安全问题产生-内因软件规模增大,功能越来越多,越来越复杂;软件模块复用,导致安全漏洞延续;软件扩展模块带来的安全问题Windows操作系统不同版本源代码数量。 软件安全问题产生-外因互联网发展对软件安全的...

    广义共振、共振解调故障诊断与安全工程

    第1章“轨道交通大发 展的时代”与第2章“轨道交通车辆的安全问题”与 城轨交通的发展 历史和当前形势接轨,搜集、调查了国际国内的若干 素材。在第3章,介绍了轨道车辆走行部常见故障。第4章 “轨道车辆走行部检测...

    DP26-用户手册.pdf

    ### DP26便携热敏标签机操作指南 ...以上是对DP26便携热敏标签机的详细介绍,包括其基本操作流程、常见问题解决方法以及重要的安全提示和技术参数等内容,希望能帮助用户更好地了解和使用这款产品。

Global site tag (gtag.js) - Google Analytics