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

Android14 应用选择器过滤指定应用 阅读详情

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

 

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

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会做很多很多事情,这里我们只看我们关注的,和这篇文章相关的部分

Java代码   收藏代码
    // 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)

Java代码   收藏代码
    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);  
        ……  
        }  
    }  


注意

Java代码   收藏代码
  1. String[] files = dir.list();  

以及之后的for循环

 

3.之后的部分比较无聊,我们直接跳到parseApplication函数部分

Java代码   收藏代码

    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的一个内部类,结构也非常简单

Java代码   收藏代码

    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)

Java代码   收藏代码

    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中

Java代码   收藏代码

    // 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)

Java代码   收藏代码

    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中

Java代码   收藏代码

    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函数

其中关键部分如下

Java代码   收藏代码

    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>

 

Java代码   收藏代码
  1. mReceiverResolver.addFilter(bf);  

在上面已经简述过了

 

 

最终所有动态注册的receiver都保存到AMS的成员变量mReceiverResolver中

Java代码   收藏代码

    /** 
     * 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)

注意

Java代码   收藏代码
  1. 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.youkuaiyun.com/su1216/


Android 14 适配之 - 隐式/显示 Intent 和 广播适配 Android 14 适配有很多方面,以上从 隐式/显示 Intent 打开组件 和 广播适配两个方面介绍适配方式。 阅读详情

相关推荐

Android广播接收器原理与最佳实践

广播接收器(BroadcastReceiver)是Android实现跨组件通信的核心机制,通过Intent实现异步消息传递。其工作原理分为标准广播和有序广播两种模式,前者全异步高效传播,后者支持优先级控制和数据修改。在Android 8.0后系统对隐式广播做出限制,开发者需注意静态注册失效和动态注册内存泄漏问题。广播机制在系统事件通知、应用间通信等场景仍具不可替代性,但需注意数据大小限制和安全性问题。现代Android开发中,可通过LocalBroadcastManager优化应用内通信,或采用ViewMo

weixin_29189987的博客 274

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

导读:本文说明系统是如何注册动态广播以及静态广播,这里主要注意其注册的顺序   这篇文章主要是针对我前两篇文章 android安全问题(四) 抢先开机启动 - 结果篇 android安全问题(五) 抢先拦截短信 - 结果篇 之前只给出了结果,并没有给出代码分析,现在给出第一步分的分析   大家都知道,广播接收器分为动态注册和静态注册两种 静态接收,就

su1216的专栏 7836

Android广播接收机制:原理、实践与优化

广播接收器(BroadcastReceiver)是Android系统中实现跨应用事件通知的核心组件,基于发布-订阅模式工作。其核心原理分为标准广播(异步执行)和有序广播(同步顺序执行)两种类型,适用于系统事件监听和应用间通信。随着Android版本演进,广播机制面临后台限制和安全性增强等挑战,开发者需要掌握静态注册与动态注册的区别,并合理处理生命周期和权限问题。在实际开发中,可通过包名限定、LocalBroadcastManager(已废弃)替代方案或观察者模式(如LiveData、RxJava)优化性能。

weixin_29188043的博客 248

Android apk不用用户点击一次的情况下接收开机广播

开机广播

wangxianlin2008的博客 1147

Android四大组件之广播(Broadcast Receiver)

一、理论基础 Broadcast Receiver是一个适用于应用程序从系统或其它应用程序接收Intent的机制。 Activity组件和Service组件具有发送广播的能力。广播接收者需要先订阅消息才能接收广播消息,任何监听Broadcast的Receiver都可以接收一个已发送的Broadcast,因此,不要在Broadcast中发送敏感信息。 广播机制是在Binder进程间通信机制的基础上实现的,在Binder进程间通信机制中,Client组件在和Service组件中通信之前Client组件事先要

武天旭的博客 829

双摄像头的实时视频拼接及目标跟踪(一)

本章主要讲图像拼接算法的研究 先膜拜一下知乎大佬全面的叙述:https://www.zhihu.com/question/34535199/answer/135169187 本文图像拼接是基于opencv的图像拼接,流程分为以下几步 ...

Y.W.jian的博客 3万+

Android组件运行时的进程名是如何确定的

一般来说一个APK中的各个组件(Activity,Service,Provider,Receiver)都是运行在同一个进程中,进程名通过一下两种方式确定:  (1) 通过AndroidManifest.xml中的application标签中android:process指定;  (2) 如果(1)中没有指定,那么进程名就是APK的包名。  当组件单独设置了进程相关的属性时,该组件便运行在不同

cauwu的专栏 2219

MDB协议中设备级别和选项(Levels and Options)

MDB协议的LEVEL级别介绍

hbstart的博客 939

Android之APP跳转权限设置界面

说明:这里为特殊情况,因为我们开发外卖平台,很多骑手不懂APP使用,安装APP时会拒绝一些权限导致APP使用不正常,这里拿骑手APP为例,需求是进入APP提示骑手是否权限都开启了,查看跳转设置权限界面,如下图: 一:实现跳转效果图: 二:实现代码 Intent intent = new Intent(); intent.setAction(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETT..

叶已初秋的博客 2万+

统信UOS服务器上,达梦DM8数据库安装避坑全记录(附大小写敏感设置)

本文详细介绍了在统信UOS服务器版上部署达梦DM8数据库的全过程,包括环境准备、安装流程、数据库实例初始化及关键参数配置,特别是大小写敏感设置的注意事项。提供了从系统配置到性能优化的完整指南,帮助用户避免常见问题,确保数据库稳定运行。

weixin_30647423的博客 332

声音特征提取--Demon谱分析(舰船水声)

不同频带的DEMON谱线相互之间也不一样,有的频带内会发生线谱遗失,有的频带内的线谱并不是真正的谱线。当舰船航速达到某个极限时,螺旋桨的高速旋转将产生空化噪声,由螺旋桨产生的一系列周期信号被空化噪声调制,在频域上表现为将低频的离散线谱线性搬移到较高频率噪声所处的频率周围,这些周期信号在频域是离散的线谱系列,对应舰船的轴频、叶频以及谐波频率,由于舰船辐射噪声低频部分还有其它噪声源,很难从低频段直接提取出螺旋桨产生的线谱系列,而是要先对高频段的调制信号进行解调,通过低通滤波得到信号的低频包络谱,即。

qq_52631753的博客 6507

Android:广播接收器(BroadCastReceiver)要点随笔。

@@@描述 广播接收器可以收到Context.sendBroadcast或者Context.sendOrderedBroadcast发出的意图(intent)。 @@@LocalBroadcastManager 如果你不需要夸应用发送广播,建议你使用LocalBroadcastManager,LocalBroadcastManager是...

186

基于ROS2系统开发机器人

以上是基于ROS 2开发机器人的基本流程和一个简单的发布者-订阅者示例。通过这个流程,你可以逐步扩展和优化你的机器人系统,实现更复杂的功能。

xuweilin的博客 1495

广播接收器android,Android广播接收器(三)

本地广播前面两篇文章Android广播接收器(一)和Android广播接收器(二)讲的都属于全局广播,即发出的广播可以被其他任何应用程序接收到,同样我们也可以接受来自其他应用程序的广播,这样就容易引起安全问题。利用本地广播就可以解决广播的安全问题,这类广播只能在应用程序的内部进行传递,并且广播接收器也只能接收来自本应用程序发出的广播。本地广播主要就是使用一个LocalBroadcastManage...

weixin_39741459的博客 230

(2)NPW(监控片)【中】---业务场景精讲

自己在日常工作当中,由于非产线人员出生,对NPW的知识一直一知半解,业务场景认识的不够透彻,做系统的时候很难理解甲方的NPW业务应用,特收集了不少关于NPW的一些业务场景,下面都是一些摘抄,大家关注我标红标粗的部分,

阿拉伯梳子的专栏 1588

路径规划 | 图解Informed RRT*算法(附ROS C++/Python/Matlab仿真)

Informed RRT*算法针对RRT*算法进行了采样优化,用椭圆采样代替全局均匀采样,避免了RRT*算法搜索树上产生过多冗余分支的缺陷。本文图解Informed RRT*原理,并提供ROS C++/Python/Matlab三种实现加深理解

FRIGIDWINTER的博客 7485

Android基础: 静态广播接收者、动态广播接收者比对

静态广播接收者、动态广播接收者对比 知识点提取出的demo: 用两种方式实现如下需求(使用动态和静态注册广播):编写一个程序,要求在activity中点击一个button,发送一个广播(该广播的intent中携带一个字符串数据),自定义一个广播接受者,接收到这个广播之后toast显示activity发送过来的内容。 相关知识点: 广播接收器可以自由地对自己感兴趣的广...

weixin_41952523的博客 669

【即插即用模块】注意力篇 | TGRS 2025 | MFA聚特征+HPDown保细节+HFF融层级,三大模块各司其职,性能翻倍!

本文介绍了MTMLNet网络中的三大核心模块:MFA(多阶段特征聚合)、HPDown(混合池化下采样)和HFF(分层特征融合)。MFA通过双尺度深度卷积和注意力机制增强特征提取能力;HPDown结合平均池化和最大池化,有效保留下采样过程中的特征信息;HFF采用三注意力机制实现自适应特征融合。这三个模块协同工作,在红外小目标检测与分割任务中取得了SOTA效果。实验表明,各模块在特征提取、信息保留和融合方面均优于传统方法,可灵活应用于各类视觉任务中。

主要更新底层视觉(去噪、超分等)相关的科研内容,形式为【论文精读】+【论文复现】 286

Broadcast与Receiver广播接收器

1、广播    1、广播的定义       广播是一种广泛运用的在应用程序之间传输信息的机制,Android中我们要发送的广播内容是一个Intent,这个Intent可以携带我们要传输的数据。广播的实现机制是比较类似于Java设计模式中的观察者模式。    2、广播的场景        A、同一app具有多个进程的不同组件之间的消息通信。        B、不同app之间的组件之间消息通信    ...

qq_27623401的博客 1075

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Android学习笔记—— 六、关于广播的基础知识

广播分为两种: 标准广播:是一种完全异步执行的广播,广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,没有先后顺序。这种广播的效率比较高,但是这也意味着它是无法截断的。 有序广播:这是一种同步执行的广播,在广播发出之后,同一时刻只有一个广播接收器能够接收到这条广播消息,当这个广播接收器中的逻辑执行完毕后广播在会继续传递。所以此时的广播是有先后顺序的,其顺序由广播接收器的注册信息...

北方提不起劲 253

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

图解Android四大组件之——广播接收器

先上一张图——整篇文章的精华 在广播接收器中是不允许开启线程的;广播是一种可以跨进程的通信方式 一.系统全局广播:发出的广播可以被其他任何应用程序接收到,也可以接收来自于其他任何应用程序的广播,因此容易引起安全问题(发送的广播被截断,接收到垃圾广播) 一)广播接收器:监听广播来得到各种系统的状态信息 1.创建: 1).新建一个类MyReceiver,继承BroadcastReceiv...

yeliner的博客 1255

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Android广播接收器

Android中的广播,即BroadcastReceiver,是应用开发中四大组件之一,通过发送/接收广播,可以实现不同组件的通信。 广播的分类 根据是否跨进程,可分为全局广播和本地广播。 全局广播:广播可以发送给不同进程,可以接收不同进程广播消息 本地广播: 使用LocalBroadcastManager.getInstance(context).sendBroadcast

twilight041132的专栏 1851

Android 使用本地广播

项目完整代码 https://github.com/Phil-tom/Android-The-First-Line-of-Code/tree/main/Chapter5 全局广播很容易引起安全性问题,为了能够简单地解决广播的安全性问题,Android引入了一套本地广播机制,使用这个机制发出的广播只能在应用程序内部传递,并且广播接收器也只能接收来自本应用程序发出的广播。 本地广播的用法并不复杂,主要使用了一个LocalBroadcastManager来对广播进行管理,并提供了发送广播和注册广播接收器的方法。

guliguliguliguli的博客 1084

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

同上篇文章一样,这里只陈述结果,代码分析稍后给出 导读:本文叙述如何先于某些伪杀毒软件、病毒、常规软件获取到短信   众所周知,android系统在收到短信息的时候会发送广播,但是此广播是有序广播,也就是说:先接收到广播的人,如果心情不好,它就不会向后传递此广播,后面的人就不会知道有短信到来 这与无序广播不同,无序广播并不是真的没有顺序(只是似乎大家习惯这么叫而已),无序广播的接

Bincker's Log 2540

Android之广播(本地广播)

Android之广播(本地广播)     前面我们发送和接收的广播全部都是属于系统全局广播, 即发出的广播可以被其他任何 的任何应用程序接收到,并且我们也可以接收来自于其他任何应用程序的广播。这样就很容 易会引起安全性的问题, 比如说我们发送的一些携带关键性数据的广播有可能被其他的应用 程序截获,或者其他的程序不停地向我们的广播接收器里发送各种垃圾广播。 为了能够简单地解决广播的安全性问

航天飞哥的博客 503

【Android成长之路】全局大喇叭——广播机制的浅谈(使用本地广播)

关于安卓引入的本地广播机制的简单讲解。

Just follow myself heart. 1799
上一篇: android安全问题(七) 抢先接收广播 - 内因篇之广播发送流程
下一篇: android安全漏洞(五) 抢先拦截短信 - 结果篇
Bincker
博客等级 码龄20年 35粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值