non-protected broadcast场景分析及解决

news2024/12/24 20:34:18

non-protected broadcast场景分析及解决

在两个app之间互相送消息使用BroadcastReceiver,有时在运行过程中在logcat工具中会发现大片的飘红消息。

要消除这些错误信息,需要在广播的 SenderReceiver 做部分的修改。

错误信息分析

由于 发送端 的 Manifest 文件中使用了android:sharedUserId=“android.uid.system”

android:sharedUserId

​ 多个app共享的一个Linux用户ID名。Android默认情况下会为每个app分配一个唯一的用户ID。而若在多个app中设置这个属性值为同一值,那么这些app共享同一个用户ID,前提是app的证书相同。有相同用户ID的apps可以互相访问彼此的数据,如果需要,他们可以运行在同一进程中。

这个属性在API 29时过时。

sharedUserId在 PackageManager 会引起不确定的行为。基于此,不鼓励sharedUserId的使用并且这个属性在未来Android的某个版本会被移除。相应地,使用适合的通信机制,例如 Service 和 ContentProvider,促使共享组件的互操作性。已经存在的apps不能直接移除这个值。在这些应用程序中,添加android:sharedUserMaxSdkVersion=“32”,以避免在新用户安装时使用共享用户ID。

发送端 设置了值 android.uid.system,在app发送广播时,会调用到 ActivityManagerService 方法 broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, String[] excludedPermissions, String[] excludedPackages, int appOp, Bundle bOptions, boolean serialized, boolean sticky, int userId)

—> broadcastIntentLocked(ProcessRecord callerApp, String callerPackage,
@Nullable String callerFeatureId, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions,
String[] excludedPermissions, String[] excludedPackages, int appOp, Bundle bOptions,
boolean ordered, boolean sticky, int callingPid, int callingUid,
int realCallingUid, int realCallingPid, int userId,
boolean allowBackgroundActivityStarts,
@Nullable IBinder backgroundActivityStartsToken,
@Nullable int[] broadcastAllowList)

在方法内针对个参数情况进行判断。

“android.uid.system” 对应与 Process.SYSTEM_UID,可以在 PackageManagerService 构造方法中查看对应关系。

   // ...   
	mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
               ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
   // 方法签名: SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) 
	// ...

在这个方法里,可以看到一段代码。

// ...
        final boolean isCallerSystem;
        switch (UserHandle.getAppId(callingUid)) {
            case ROOT_UID:
            case SYSTEM_UID: // android.uid.system 值,可以在PackageManagerService构造方法中查看映射关系
            case PHONE_UID:
            case BLUETOOTH_UID:
            case NFC_UID:
            case SE_UID:
            case NETWORK_STACK_UID:
                isCallerSystem = true; // 发送的app使system app
                break;
            default:
                isCallerSystem = (callerApp != null) && callerApp.isPersistent();
                break;
        }

        // First line security check before anything else: stop non-system apps from
        // sending protected broadcasts.
        if (!isCallerSystem) { // 若不是 system app,而发送的是protected broadcast,进程会抛出SecurityException
            if (isProtectedBroadcast) {
                String msg = "Permission Denial: not allowed to send broadcast "
                        + action + " from pid="
                        + callingPid + ", uid=" + callingUid;
                Slog.w(TAG, msg);
                throw new SecurityException(msg);

            } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
                    || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
                // Special case for compatibility: we don't want apps to send this,
                // but historically it has not been protected and apps may be using it
                // to poke their own app widget.  So, instead of making it protected,
                // just limit it to the caller.
                if (callerPackage == null) {
                    String msg = "Permission Denial: not allowed to send broadcast "
                            + action + " from unknown caller.";
                    Slog.w(TAG, msg);
                    throw new SecurityException(msg);
                } else if (intent.getComponent() != null) {
                    // They are good enough to send to an explicit component...  verify
                    // it is being sent to the calling app.
                    if (!intent.getComponent().getPackageName().equals(
                            callerPackage)) {
                        String msg = "Permission Denial: not allowed to send broadcast "
                                + action + " to "
                                + intent.getComponent().getPackageName() + " from "
                                + callerPackage;
                        Slog.w(TAG, msg);
                        throw new SecurityException(msg);
                    }
                } else {
                    // Limit broadcast to their own package.
                    intent.setPackage(callerPackage);
                }
            }
        }
		// ...


        if (isCallerSystem) { // System app会检查
            // 调用到这个方法内,就可以看到最后在logcat中看到的 non-protected broadcast 字样的信息
            checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
                    isProtectedBroadcast, receivers);
        }

看下具体的 checkBroadcastFromSystem()方法。

    private void checkBroadcastFromSystem(Intent intent, ProcessRecord callerApp,
            String callerPackage, int callingUid, boolean isProtectedBroadcast, List receivers) {
        if ((intent.getFlags() & Intent.FLAG_RECEIVER_FROM_SHELL) != 0) {
            // Don't yell about broadcasts sent via shell
            return;
        }

        final String action = intent.getAction();
        if (isProtectedBroadcast // 是否是定义的protected broadcast
                || Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
                || Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS.equals(action)
                || Intent.ACTION_MEDIA_BUTTON.equals(action)
                || Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)
                || Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(action)
                || Intent.ACTION_MASTER_CLEAR.equals(action)
                || Intent.ACTION_FACTORY_RESET.equals(action)
                || AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
                || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)
                || TelephonyManager.ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE.equals(action)
                || SuggestionSpan.ACTION_SUGGESTION_PICKED.equals(action)
                || AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION.equals(action)
                || AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION.equals(action)) {
            // Broadcast is either protected, or it's a public action that
            // we've relaxed, so it's fine for system internals to send.
            return;
        }

        // This broadcast may be a problem...  but there are often system components that
        // want to send an internal broadcast to themselves, which is annoying to have to
        // explicitly list each action as a protected broadcast, so we will check for that
        // one safe case and allow it: an explicit broadcast, only being received by something
        // that has protected itself.
        if (intent.getPackage() != null || intent.getComponent() != null) { // 基于package和组件判断
            if (receivers == null || receivers.size() == 0) {
                // Intent is explicit and there's no receivers.
                // This happens, e.g. , when a system component sends a broadcast to
                // its own runtime receiver, and there's no manifest receivers for it,
                // because this method is called twice for each broadcast,
                // for runtime receivers and manifest receivers and the later check would find
                // no receivers.
                return;
            }
            boolean allProtected = true;
            for (int i = receivers.size()-1; i >= 0; i--) {
                Object target = receivers.get(i);
                if (target instanceof ResolveInfo) { // 从Manifest解析获得ResolveInfo对象
                    ResolveInfo ri = (ResolveInfo)target;
                    if (ri.activityInfo.exported && ri.activityInfo.permission == null) {
                        allProtected = false;
                        break;
                    }
                } else {
                    BroadcastFilter bf = (BroadcastFilter)target; // 基于IntentFilter的解析
                    if (bf.exported && bf.requiredPermission == null) {
                        allProtected = false;
                        break;
                    }
                }
            }
            if (allProtected) {
                // All safe!
                return;
            }
        }

        // The vast majority of broadcasts sent from system internals
        // should be protected to avoid security holes, so yell loudly
        // to ensure we examine these cases.
        if (callerApp != null) { // 在判断 allProtected 不能是 true 值下,打印错误信息。
            Log.wtf(TAG, "Sending non-protected broadcast " + action
                            + " from system " + callerApp.toShortString() + " pkg " + callerPackage,
                    new Throwable());
        } else {
            Log.wtf(TAG, "Sending non-protected broadcast " + action
                            + " from system uid " + UserHandle.formatUid(callingUid)
                            + " pkg " + callerPackage,
                    new Throwable());
        }
    }

至此,可以看到打印错误信息的位置。

解决方法

打印 "Sending non-protected broadcast " 信息的错误,主要在于Broadcast注册方式及exportedpermission这两个值。对于非系统预定义的protected broadcasts,或个别定义的broadcats,必须有eported ,permission值。

Sender 端:

在Manifest中定义permission,使用 sendBroadcast(Intent intent, String receiverPermission) 方法。

Receiver 端:

在注册receiver时,使用 registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) 带有permission参数的方法,参数 broadcastPermission 即是在 Sender 端定义的permission。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/563740.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

忆享聚焦|ChatGPT、AI、网络数字、游戏……近期热点资讯一览

“忆享聚焦”栏目第十四期来啦!本栏目汇集近期互联网最新资讯,聚焦前沿科技,关注行业发展动态,筛选高质量讯息,拓宽用户视野,让您以最低的时间成本获取最有价值的行业资讯。 目录 行业资讯 1.科技部部长王志…

上海亚商投顾:沪指跌1.28%失守年线 大金融板块集体走弱

上海亚商投顾前言:无惧大盘涨跌,解密龙虎榜资金,跟踪一线游资和机构资金动向,识别短期热点和强势个股。 市场情绪 三大指数今日继续调整,沪指超1%逼近3200点,尾盘失守年线,创业板指较为抗跌。大…

你收藏了那些实用工具类网站?

今天来给大家分享几个众多网友们推荐的,宝藏工具类网站 uIGradients https://uigradients.com/#Flickr 专业的渐变色配色工具网站,配色什么的非常全,也可以按照自己的想法来选择搭配,还能直接获得对应渐变配色的CSS代码&#xff…

水表自动抄表系统有什么功能

水表自动抄表系统是一种新型的智能化管理系统,它可以自动采集水表的数据,并且实时上传到管理平台,实现了水表的实时监测和管理。该系统具有以下几个主要功能: 1.自动抄表功能 水表自动抄表系统可以实现自动采集水表的数据&#x…

【学习笔记】Windows 下线程同步之互斥锁

目录 前言环境简介相关函数CreateMutex Wait 函数ReleaseMutexCloseHandle 其他互斥锁的名字未命名互斥锁的同步互斥锁的意外终止临界区对象 参考 前言 本文所涉及的同步主要描述在 Windows 环境下的机制,和 Linux 中的同步机制有一定的联系,但注意并不…

小猫踩球-第14届蓝桥杯省赛Scratch中级组真题第2题

[导读]:超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成,后续会不定期解读蓝桥杯真题,这是Scratch蓝桥杯真题解析第137讲。 小猫踩球,本题是2023年5月7日举行的第14届蓝桥杯省赛Scratch图形化编程中级组真题第2题&#xf…

智慧档案馆一体化监控系统设计所需要的10条依据

1.科学性 本项目目标定位为:以科学技术为基础,依靠先进的设备和优越的设计理念、科学客观的管理,利用信息化管理及相关最新技术,将库房实际环境与存储技术、计算机技术、无线自动控制技术、通讯与信息处理技术等先进技术相结合&a…

Python appium搭建app自动化测试环境

目录 前言 App自动化环境安装 安装安卓开发工具 安装模拟器 前言 appium做app自动化测试,环境搭建是比较麻烦的。 也是很多初学者在学习app自动化之时,花很多时间都难跨越的坎。 但没有成功的环境,就没有办法继续后续的使用。 在app自…

面试技术点

一、对热修复、插件化、模块化、组件化有一定研究。 1、模块化 将共享部分或业务模块抽取出来形成独立module。 2、组件化 基于模块化,核心思想是角色的转换,在打包时是library,分离独立的业务组件如微信朋友圈。 3、热修复和插件化种类、…

在Kaggle上使用Stable Diffusion进行AI绘图

前言 因为使用Stable Diffusion进行AI绘图需要GPU,这让其应用得到了限制本文介绍如何在Kaggle中部署Stable Diffusion,并使用免费的P100 GPU进行推理(每周可免费使用30小时),部署好后可以在任意移动端使用。本项目在s…

2023全球最佳医院榜单及简要介绍

作为医学类的访问学者、博士后及联合培养博士们,都希望到世界知名医院进行临床研修交流及科研学习。2023 年世界最佳医院排行榜的发布为申请者提供了目标平台,现知识人网小编整理刊出。 近期,《新闻周刊》和全球数据公司 Statista 推出了2023…

拿了7家大厂offer后,整理出来的笔记.....

我第一次接触自动化是在2016年。那时刚毕业一年有余,组内一直做手工功能测试,大概在2018年9月,部门领导要求测试组引入自动化。组内之前从没有开展过任何自动化,测试主管安排了一个刚入职不久的研究生同事去研究。 当时自己内心还…

UniApp原生插件制作

参考1:UniApp官网-原生插件开发 参考2:uniapp Android 原生插件开发 一、下载安装Android Studio 本部分不在赘述 二、下载UniApp离线SDK 下载地址:Android 离线SDK - 正式版 | uni小程序SDK 三、解压下载文件,并导入Androi…

蓝精灵协会:如何将传统 IP 融入 Web3

作者:Cedric Hervet,联合创始人,创意总监 我和许多项目合作过,并且担任了近 30 年的艺术总监和创意总监。我的方法一直是创造同质化的宇宙,把观众带入并使他们产生梦想。但我也曾系统地寻找过那份额外的感动&#xff1…

微服务解码:揭示API的优势挑战与最佳实践

在当今快节奏的软件开发环境中,微服务已成为一种流行的架构模式。但微服务到底是什么?简而言之,微服务是一种将应用程序构建为松耦合、细粒度服务集合的方式,这些服务通过轻量级协议进行通信。这种架构风格使团队能够独立开发和部…

el-upload上传图片成功,详情页回显base64格式的图片

上传图片,并传给后端图片格式是base64。在详情页需要回显图片在el-upload上,我们发现官网里图片回显时,文件数组里要配置好name和url,如下图: 当我们需要回显base64格式的图片时,我们需要将要回显的文件数组处理成id和…

00后竭尽全力面试腾讯软件测试工程师,难道我只值15k....

不废话,直接重点 一般软件测试的面试分为三轮:笔试,HR面试,技术面试。 前两轮,根据不同企业,或有或无,但最后一个技术面试是企业了解你“行不行”的关键环节,每个企业都会有的。 在…

ChatGPT可能马上取代你!ChatGPT能做什么?

文章目录 前言1.客服机器人2.智能助手3.内部沟通4.个性化推荐5.语音交互6.教育培训7.医疗健康8.社交娱乐9.营销推广10.情感分析11.舆情监测12.知识管理13.金融服务14.物联网15.公共服务16.智能家居17.自动化办公18.交通出行19.游戏娱乐20.智慧城市21.决策支持22.人才招聘23.版权…

圣墟传说H5手工端搭建架设教程

圣墟传说H5手工端搭建架设教程 大家好,我是艾西。今天给大家带来的游戏是由小说改编而来的大型玄幻MMORPG仙侠手游,也是比较老的游戏了虽然你可能没有怎么听过,但总会有一批喜欢的玩家热衷于它。 那么让我们直接进入正题开始操作&#xff1…

ChatGPT:你真的了解网络安全吗?浅谈攻击防御进行时之网络安全新总结

ChatGPT:你真的了解网络安全吗?浅谈网络安全攻击防御进行时 网络安全新总结总结 ChatGPT(全名:Chat Generative Pre-trained Transformer),美国OpenAI 研发的聊天机器人程序,是人工智能技术驱动…