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

android安全问题(七) 抢先接收广播 - 内因篇之广播发送流程

阅读更多

导读:本文说明系统发送广播的部分流程,如何利用Intent查找到对应接收器。我们依然只关注接收器的排序问题

 

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

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

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

现在给出第二步分的分析

 

 

下面就来看看发送广播的流程

Context中的sendBroadCast函数的实现是在ContextImpl中,和发送广播相关的有如下六个函数

void android.app.ContextImpl.sendBroadcast(Intent intent)

void android.app.ContextImpl.sendBroadcast(Intent intent, String receiverPermission)

void android.app.ContextImpl.sendOrderedBroadcast(Intent intent, String receiverPermission)

void android.app.ContextImpl.sendOrderedBroadcast(Intent intent, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)

void android.app.ContextImpl.sendStickyBroadcast(Intent intent)

void android.app.ContextImpl.sendStickyOrderedBroadcast(Intent intent, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)

 

可以分为3组:1普通广播;2Ordered广播;3Sticky广播

不论哪种,最后都会由ActivityManagerService处理

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)

以第一种情况为例,流程图大概是这个样子的

 

ordered和sticky用来区分上面3组广播

下面我们仔细看看这个方法都干了些什么

删减了一些代码

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) {
    ...//处理特殊intent
    // Add to the sticky list if requested.
    ...//处理sticky广播
    // Figure out who all will receive this broadcast.
    List receivers = null;
    List<BroadcastFilter> registeredReceivers = 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) {
        // pm is in same process, this will never happen.
    }

    final boolean replacePending =
            (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
    ...
    int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
    ...//如果广播是非ordered,先处理动态注册的接收器
    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.
        BroadcastRecord r = new BroadcastRecord(intent, callerApp,
                callerPackage, callingPid, callingUid, requiredPermission,
                registeredReceivers, resultTo, resultCode, resultData, map,
                ordered, sticky, false);
        ...
	//mParallelBroadcasts只含有动态注册的receiver
        boolean replaced = false;
        if (replacePending) {
            for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
                if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
                    if (DEBUG_BROADCAST) Slog.v(TAG,
                            "***** DROPPING PARALLEL: " + intent);
                    mParallelBroadcasts.set(i, r);
                    replaced = true;
                    break;
                }
            }
        }
        if (!replaced) {
            mParallelBroadcasts.add(r);
            scheduleBroadcastsLocked();
        }
        registeredReceivers = null;
        NR = 0;
    }

    // Merge into one list.
    //如果广播是ordered,合并静态、动态接收器
    //否则之前处理过动态接收器,这里registeredReceivers为null
    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);
            }
            //如果动态接收器优先级高,那么就插到前面
            //否则进入else,然后进行下一轮比较,拿下一个静态接收器与之前的动态接收器比较,直到找到自己的位置才插入进列表中
            //在这里,调整好接收器的顺序,同等优先级的,显然动态的要在静态的前面
            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) {
        BroadcastRecord r = new BroadcastRecord(intent, callerApp,
                callerPackage, callingPid, callingUid, requiredPermission,
                receivers, resultTo, resultCode, resultData, map, ordered,
                sticky, false);
        ...
        if (!replaced) {
            mOrderedBroadcasts.add(r);
            scheduleBroadcastsLocked();
        }
    }

    return BROADCAST_SUCCESS;
}

注意上面函数中提到的其中两个成员变量

/**
 * List of all active broadcasts that are to be executed immediately
 * (without waiting for another broadcast to finish).  Currently this only
 * contains broadcasts to registered receivers, to avoid spinning up
 * a bunch of processes to execute IntentReceiver components.
 */
final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<BroadcastRecord>();


/**
 * List of all active broadcasts that are to be executed one at a time.
 * The object at the top of the list is the currently activity broadcasts;
 * those after it are waiting for the top to finish..
 */
final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<BroadcastRecord>();

如果是非ordered广播,那么mParallelBroadcasts将存储所有动态接收器,然后合并的时候,mParallelBroadcasts设置为null,所以不会合并到receivers中

如果是ordered广播,那么mParallelBroadcasts将合并到receivers中

然后,不管是哪种广播,最后都是调用scheduleBroadcastsLocked继续处理

最终到processNextBroadcast函数上

在看processNextBroadcast函数之前,还有个问题需要解决

receivers = AppGlobals.getPackageManager().queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS);

registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);

那就是查询出来的List是什么顺序,之后的处理过程上面都已经看到了,但是这里面是什么顺序我们还没有看到

先看看动态注册的Receiver情况

public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly) {
    String scheme = intent.getScheme();

    ArrayList<R> finalList = new ArrayList<R>();
    ...
    ArrayList<F> firstTypeCut = null;
    ArrayList<F> secondTypeCut = null;
    ArrayList<F> thirdTypeCut = null;
    ArrayList<F> schemeCut = null;

    //下面是一些匹配的细节,我们先不关注
    // If the intent includes a MIME type, then we want to collect all of
    // the filters that match that MIME type.
    //这里不涉及MIME,所以这里resolvedType=null
    if (resolvedType != null) {
        ...
    }

    // If the intent includes a data URI, then we want to collect all of
    // the filters that match its scheme (we will further refine matches
    // on the authority and path by directly matching each resulting filter).
    if (scheme != null) {
        schemeCut = mSchemeToFilter.get(scheme);
        if (debug) Slog.v(TAG, "Scheme list: " + schemeCut);
    }

    // If the intent does not specify any data -- either a MIME type or
    // a URI -- then we will only be looking for matches against empty
    // data.
    if (resolvedType == null && scheme == null && intent.getAction() != null) {
        firstTypeCut = mActionToFilter.get(intent.getAction());//在addFilter的时候将其add进去,见上一篇博客
        if (debug) Slog.v(TAG, "Action list: " + firstTypeCut);
    }

    FastImmutableArraySet<String> categories = getFastIntentCategories(intent);
    //finalList就是我们的结果集
    if (firstTypeCut != null) {
        //buildResolveList循环List,检查是否符合条件,然后复制到finalList中
        buildResolveList(intent, categories, debug, defaultOnly,
                resolvedType, scheme, firstTypeCut, finalList);
    }
    if (secondTypeCut != null) {
        buildResolveList(intent, categories, debug, defaultOnly,
                resolvedType, scheme, secondTypeCut, finalList);
    }
    if (thirdTypeCut != null) {
        buildResolveList(intent, categories, debug, defaultOnly,
                resolvedType, scheme, thirdTypeCut, finalList);
    }
    if (schemeCut != null) {
        buildResolveList(intent, categories, debug, defaultOnly,
                resolvedType, scheme, schemeCut, finalList);
    }
    sortResults(finalList);
    ...
    return finalList;
}

 

这里我们也看到关于排序代码,具体如下,很简单 

@SuppressWarnings("unchecked")
protected void sortResults(List<R> results) {
    Collections.sort(results, mResolvePrioritySorter);
}

// Sorts a List of IntentFilter objects into descending priority order.
@SuppressWarnings("rawtypes")
private static final Comparator mResolvePrioritySorter = new Comparator() {
    public int compare(Object o1, Object o2) {
        final int q1 = ((IntentFilter) o1).getPriority();
        final int q2 = ((IntentFilter) o2).getPriority();
        return (q1 > q2) ? -1 : ((q1 < q2) ? 1 : 0);
    }
};

上面就是简单的按优先级排序,大的放在前面,否则位置不动

 

下面看看静态注册的Receiver情况,最终也会和动态注册的Receiver一样,调用同一个函数

public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags) {
    //ComponentName之后应该均为null,我们不讨论只发给特定组件的情况,因为那样不涉及优先级和顺序的问题
    ComponentName comp = intent.getComponent();
    if (comp == null) {
        if (intent.getSelector() != null) {
            intent = intent.getSelector(); 
            comp = intent.getComponent();
        }
    }
    if (comp != null) {
        List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
        ActivityInfo ai = getReceiverInfo(comp, flags);
        if (ai != null) {
            ResolveInfo ri = new ResolveInfo();
            ri.activityInfo = ai;
            list.add(ri);
        }
        return list;
    }

    // reader
    //ComponentName=null,所以会执行下面代码
    synchronized (mPackages) {
        String pkgName = intent.getPackage();
        //只考虑pkgName=null的情况,同一个package中,哪个receiver先接收到广播暂时不关心
        if (pkgName == null) {
            return mReceivers.queryIntent(intent, resolvedType, flags);//最终会调用IntentResolver.queryIntent,上面已经分析过
        }
        final PackageParser.Package pkg = mPackages.get(pkgName);
        if (pkg != null) {
            return mReceivers.queryIntentForPackage(intent, resolvedType, flags, pkg.receivers);
        }
        return null;
    }
}

现在看来,上面两个查询都是按优先级从高到低排序的,如果优先级相同,顺序则保持不变

之后是调用scheduleBroadcastsLocked来发广播给每一个receiver

至于广播后续如何处理,我们就不再深究了

到这里已经能看到应用中的接收顺序了

 

总结:

情况分为两种(scheduleBroadcastsLocked),ordered广播和非ordered广播

非ordered广播

先处理动接收器,然后处理静态接收器

ordered广播

同时处理动态接收器和静态接收器

先将动态接收器与静态接收器合并,保持着与优先级相同的顺序,优先级高的在前面,否则顺序不变。静态接收器与动态接收器优先级相同的话,动态接收器在前

 

 

转贴请保留以下链接

本人blog地址

http://su1216.iteye.com/

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

2
0
分享到:
评论

相关推荐

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

    为了矿井内因火灾防治工作更好更快的发展,结合矿井内因...并从加强基础理论研究、加快新型材料及工艺设备研发2个方面进行了矿井内因火灾防治技术发展方向的展望,以保障煤矿安全生产及推动煤炭工业的健康可持续发展。

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

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

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

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

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

    通过对矿井内因火灾事故的条件与特性进行分析,运用预先危险性分析的方法辨别出矿井内因火灾的危险性类型、触发条件、隐患位置及可能造成的后果,结合矿井的实际安全条件建立矿井内因火灾的预先危险性分析表,并提出...

    医药流通行业深度:内因外因逐步改善,底部精选核心资产-0806-安信证券-21页.pdf

    医药流通行业深度:内因外因逐步改善,底部精选核心资产-0806-安信证券-21页.pdf

    计算机网络安全问题分析及对策.docx

    毫不夸张的说,如果一台电脑没有安装杀毒软件就连接了互联网,则其很可能在几天内甚至数小时内因感染病毒而导计算机网络安全问题分析及对策全文共5页,当前为第3页。计算机网络安全问题分析及对策全文共5页,当前为...

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

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

    神东矿区内因火灾防治探讨

    神东矿区煤层埋藏较浅,层间距较近,煤层近似水平,采动后易形成大面积多层复合采空区,导致各层均具有自然发火可能性,...针对不同类型内因火灾给出常规防治技术路线,以期可杜绝神东矿区内因火灾事故,保证矿井安全生产。

    矿井内因火灾的安全评价研究——基于熵值法和突变理论-论文

    针对矿井内因火灾的突发性、不确定性和高危害性等特点,提出熵值法和突变理论相结合的矿井内因火灾安全评价方法。选取人、物、环境和管理4个方面的因素建立了4级共20个评价指标的矿井内因火灾安全评价指标体系,运用...

    软件开发文档-开发流程..

    提示:从内因、外因两方面阐述产品开发背景,重点说明“为什么”要开发本产品。 (1)因方面着重考虑:开发方的短期、长期发展战略;开发方的当前实力。 (2)外因方面着重考虑:市场需求及发展趋势;技术状况及发展...

    信息安全和保障

    信息安全是综合性的、全方位的,它涉及技术、管理、法律、社会和国家,产生的原因也多样性的,归纳主要为两个方面:既有天然脆弱性的内因,也有人为复杂的外因,所以其保障必然会是综合性和全方位的。

    煤矿工人安全认知与不安全行为关系研究

    煤矿工人安全认知是影响不安全行为的重要内因之一,为了探索安全认知与矿工不安全行为之间的关系,根据相关文献分析并结合煤矿作业环境,将安全认知划分为现场危险认知、工友风险行为认知、职业安全认知和规章制度认知4...

    乌达煤田煤层自燃内因分析与自燃类型划分

    采用野外地质调查、测试分析和数据处理等综合手段,研究内蒙古乌达煤田煤层自然发火的内因条件,揭示了煤层自燃趋向性与煤层厚度、煤变质程度、灰分含量、发热量、硫含量、硫化物矿物以及有机显微组分含量等煤物质组成...

    复杂通风网络角联风流安全稳定性评价与控制

    针对复杂通风网络中角联分支风流安全稳定性问题,从影响角联风流稳定性的内因、外因以及安全性因素方面建立了评价指标体系,运用层次分析法确定了各指标权重,提出角联风流安全稳定性的模糊优选评价法。从提高角联分支...

    七台河分公司矿井内因火灾的防治探讨

    对煤层自燃机理的分析及其自燃存在的危害,结合七台河分公司的有效做法,对其在内因火灾防治方面的做法进行分析探讨,根据矿区的实际情况,分公司在防治自然发火措施方面按照安全、经济、效益的原则,做到分析全面、方向...

    量温检测技术在采空区内因火灾预报中的应用

    采煤工作面采空区不可避免地要有可燃煤的存在,采空区漏风流场供氧条件下,自燃破碎的煤极易形成内因火灾,严重影响着矿井的安全生产。采用温度观测法辅助预报手段,可以及时掌控采空区内部状况及采空区内煤体氧化规律,...

    基于SEM的矿工不安全行为形成机理研究

    在分析矿工不安全行为形成原因的基础上,从内因和外因2个因素层面提出假设,构建矿工不安全行为形成机理初步模型。运用结构方程对矿工不安全行为形成机理初步模型进行验证,最终得到矿工不安全行为形成机理的最终模型,...

Global site tag (gtag.js) - Google Analytics