android 11+后台启动FGS的while-in-use权限限制

news2024/12/23 4:08:47

while-in-use权限限制

为了帮助保护用户隐私,Android 11(API 级别 30)对前台服务何时可以访问设备的位置、摄像头或麦克风进行了限制。 当您的应用程序在后台运行时启动前台服务时,前台服务有以下限制:

  • 除非用户已向您的应用授予 ACCESS_BACKGROUND_LOCATION 权限,否则前台服务无法访问位置。
  • 前台服务无法访问麦克风或摄像头。

确定您的应用程序中哪些服务受到影响

测试您的应用程序时,启动其前台服务。 如果启动的服务限制了对位置、麦克风和摄像头的访问,Logcat 中会显示以下消息:
Foreground service started from background can not have location/camera/microphone access: service SERVICE_NAME

限制原理

FGS 有两个限制:
在 R 中,mAllowWhileInUsePermissionInFgs 是允许在前台服务中使用 while-in-use 权限。 从后台启动的 FGS 中的使用中权限可能会受到限制。
在S中,mAllowStartForeground是允许FGS是否startForeground。 从后台启动的服务可能不会成为 FGS。具体见后台启动FGS限制

启动或绑定或调用startForeground时会调用setFgsRestrictionLocked方法去校验上面的两个FGS限制。
在这里插入图片描述

private void setFgsRestrictionLocked(String callingPackage,
        int callingPid, int callingUid, Intent intent, ServiceRecord r, int userId,
        boolean allowBackgroundActivityStarts) {
    	.......
    if (!r.mAllowWhileInUsePermissionInFgs
            || (r.mAllowStartForeground == REASON_DENIED)) {
        // while in use权限校验
        final @ReasonCode int allowWhileInUse = shouldAllowFgsWhileInUsePermissionLocked(
                callingPackage, callingPid, callingUid, r, allowBackgroundActivityStarts);
        if (!r.mAllowWhileInUsePermissionInFgs) {
            r.mAllowWhileInUsePermissionInFgs = (allowWhileInUse != REASON_DENIED);
        }
        // 是否允许后台启动FGS校验
       .......
    }

如果前台服务不是从 TOP 进程启动的,则不允许它在使用中访问位置/相机/麦克风。

if (!r.mAllowWhileInUsePermissionInFgs) {
    Slog.w(TAG,
            "Foreground service started from background can not have "
                    + "location/camera/microphone access: service "
                    + r.shortInstanceName);
}

限制豁免

在某些情况下,即使应用程序在后台运行时启动了前台服务,它仍然可以在应用程序在前台运行时(“使用中”)访问位置、摄像头和麦克风信息。 在这些相同的情况下,如果该服务声明了前台服务类型的位置并由具有 ACCESS_BACKGROUND_LOCATION 权限的应用程序启动,则该服务可以一直访问位置信息,即使该应用程序在后台运行时也是如此。

是否应允许 FGS 中的使用中权限。 一个典型的 BG 启动的 FGS 不允许有 while-in-use 权限

该服务由前台应用启动

跟 后台启动FGS限制-应用程序在前台 一样

  • REASON_PROC_STATE_PERSISTENT
  • REASON_PROC_STATE_PERSISTENT_UI
  • REASON_PROC_STATE_TOP
private @ReasonCode int shouldAllowFgsWhileInUsePermissionLocked(String callingPackage,int callingPid, int callingUid, @Nullable ServiceRecord targetService,
    boolean allowBackgroundActivityStarts) {
    int ret = REASON_DENIED;

    final int uidState = mAm.getUidStateLocked(callingUid);
    if (ret == REASON_DENIED) {
            // Is the calling UID at PROCESS_STATE_TOP or above?
        if (uidState <= PROCESS_STATE_TOP) {
            ret = getReasonCodeFromProcState(uidState);
        }
    }

该服务由可见应用启动

类似后台启动FGS限制-应用程序可见

  • REASON_UID_VISIBLE
        if (ret == REASON_DENIED) {
            // Does the calling UID have any visible activity?
            final boolean isCallingUidVisible = mAm.mAtmInternal.isUidForeground(callingUid);
            if (isCallingUidVisible) {
                ret = REASON_UID_VISIBLE;
            }
        }

该服务通过与通知交互来启动

该服务作为从不同的可见应用程序发送的 PendingIntent 启动

同后台启动FGS限制-该服务通过与通知交互来启动

  • REASON_START_ACTIVITY_FLAG
        if (ret == REASON_DENIED) {
            // Is the allow activity background start flag on?
            if (allowBackgroundActivityStarts) {
                ret = REASON_START_ACTIVITY_FLAG;
            }
        }

该服务由系统组件启动(root/system/nfc/shell)

  • REASON_SYSTEM_UID

同 后台启动FGS限制-该服务由系统组件启动

        if (ret == REASON_DENIED) {
            boolean isCallerSystem = false;
            final int callingAppId = UserHandle.getAppId(callingUid);
            switch (callingAppId) {
                case ROOT_UID:
                case SYSTEM_UID:
                case NFC_UID:
                case SHELL_UID:
                    isCallerSystem = true;
                    break;
                default:
                    isCallerSystem = false;
                    break;
            }

            if (isCallerSystem) {
                ret = REASON_SYSTEM_UID;
            }
        }

该服务由具有 START_ACTIVITIES_FROM_BACKGROUND 特权权限的应用程序启动

同后台启动FGS限制

  • REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION
  • REASON_BACKGROUND_ACTIVITY_PERMISSION
        if (ret == REASON_DENIED) {
            if (targetService != null && targetService.app != null) {
                ActiveInstrumentation instr = targetService.app.getActiveInstrumentation();
                if (instr != null && instr.mHasBackgroundActivityStartsPermission) {
                    ret = REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
                }
            }
        }
        if (ret == REASON_DENIED) {
            if (mAm.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
                    == PERMISSION_GRANTED) {
                ret = REASON_BACKGROUND_ACTIVITY_PERMISSION;
            }
        }

该服务由系统Captions Service/Attention Service应用启动

  • REASON_ALLOWLISTED_PACKAGE
if (ret == REASON_DENIED) {
    if (verifyPackage(callingPackage, callingUid)) {
        final boolean isAllowedPackage =
                mAllowListWhileInUsePermissionInFgs.contains(callingPackage);
        if (isAllowedPackage) {
            ret = REASON_ALLOWLISTED_PACKAGE;
        }
    } else {
        EventLog.writeEvent(0x534e4554, "215003903", callingUid,
        	"callingPackage:" + callingPackage + " does not belong to callingUid:"
                        + callingUid);
    }
}
private void setAllowListWhileInUsePermissionInFgs() {
    final String attentionServicePackageName =
            mAm.mContext.getPackageManager().getAttentionServicePackageName();
    if (!TextUtils.isEmpty(attentionServicePackageName)) {
        mAllowListWhileInUsePermissionInFgs.add(attentionServicePackageName);
    }
    final String systemCaptionsServicePackageName =
            mAm.mContext.getPackageManager().getSystemCaptionsServicePackageName();
    if (!TextUtils.isEmpty(systemCaptionsServicePackageName)) {
        mAllowListWhileInUsePermissionInFgs.add(systemCaptionsServicePackageName);
    }
}

该服务由应用程序启动,该应用程序是在设备所有者模式下运行的设备策略控制器。

  • REASON_DEVICE_OWNER
        if (ret == REASON_DENIED) {
            // Is the calling UID a device owner app?
            final boolean isDeviceOwner = mAm.mInternal.isDeviceOwner(callingUid);
            if (isDeviceOwner) {
                ret = REASON_DEVICE_OWNER;
            }
        }

该服务由MediaSeesion相关的应用启动

        if (ret == REASON_DENIED) {
            if (mAm.mInternal.isTempAllowlistedForFgsWhileInUse(callingUid)) {
                return REASON_TEMP_ALLOWED_WHILE_IN_USE;
            }
        }
if (canAllowWhileInUse) {
    mActivityManagerLocal.tempAllowWhileInUsePermissionInFgs(targetUid,
            MediaSessionDeviceConfig
                    .getMediaSessionCallbackFgsWhileInUseTempAllowDurationMs());
}

关于areBackgroundActivityStartsAllowed系列

同 后台启动FGS限制

该服务由某个 Activity 刚在不久前启动/结束的应用启动

该服务由运行后台启动activity特权的Active Instrumentation的应用启动

该服务由在前台任务的返回栈中拥有 Activity的应用启动

该服务由某个服务被另一个可见应用绑定的应用启动

  • REASON_ACTIVITY_STARTER
        if (ret == REASON_DENIED) {
            final Integer allowedType = mAm.mProcessList.searchEachLruProcessesLOSP(false, pr -> {
                if (pr.uid == callingUid) {
                    if (pr.getWindowProcessController().areBackgroundFgsStartsAllowed()) {
                        return REASON_ACTIVITY_STARTER;
                    }
                }
                return null;
            });
            if (allowedType != null) {
                ret = allowedType;
            }
        }

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

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

相关文章

智能家居创意产品一智能插座

WiFi智能插座对于新手接触智能家居产品更加友好&#xff0c;不需要额外购买网关设备 很多智能小配件也给我们得生活带来极大的便捷&#xff0c;智能插座就是其中之一&#xff0c;比如外出忘记关空调&#xff0c;可以拿起手机远程关闭。 简单说就是&#xff1a;插座可以连接wi…

python深拷贝和浅拷贝

python深拷贝和浅拷贝&#xff08;一&#xff09; 定义 直接赋值&#xff1a;其实就是对象的引用。浅拷贝&#xff1a;拷贝父对象&#xff0c;不会拷贝对象的内部的子对象。深拷贝&#xff1a; copy 模块的 deepcopy 方法&#xff0c;完全拷贝了父对象及其子对象。 浅拷贝&am…

【自学C++】C++变量

C变量 C变量教程 不论是使用哪种高级程序语言编写程序&#xff0c;变量都是其程序的基本组成单位。变量相当于内存中一个数据存储空间的表示&#xff0c;通过变量名可以访问到变量的具体的值。 C 的变量&#xff08;variable&#xff09;是有明确 类型 的。编译器会检查 函数…

Linux 安装OpenSSL及解决遇到的问题

OpenSSL下载openssl安装包解压配置相应检查编译安装测试创建软链接N次测试下载openssl安装包 wget https://www.openssl.org/source/openssl-3.0.1.tar.gz执行后如果拉不下来&#xff0c;出现证书过期 需要加上 --no-check-certificate 不做检查 wget https://www.openssl.o…

C语言char类型的存储

目录char是如何存储的char的类型char的取值范围例题char是如何存储的 字符型&#xff08;char&#xff09;用于储存字符&#xff08;character&#xff09;&#xff0c;如英文字母或标点。但是char类型在内存中并不是以字符的形式储存&#xff0c;而是以ASII码的形式储存&…

python对接API二次开发高级实战案例解析:Zabbix API封装类实现获取认证密钥、所有主机组、所有主机、所有监控项和历史数据

Zabbix API是基于Web的API&#xff0c;作为Web前端的一部分提供。它使用JSON-RPC 2.0协议&#xff0c;这意味着两点&#xff1a; 该API包含一组独立的方法&#xff1b;客户端和API之间的请求和响应使用JSON格式进行编码。 传送门&#xff1a;Zabbix API官方文档 导入模块 在za…

单线程Reactor模型

单线程Reactor模型 Reactor模型只是对select\poll\epoll等网络模型的封装&#xff0c;本文讲解基于epoll实现Reactor模型 Reactor模型 单线程Reactor模型较为简单&#xff0c;如图&#xff1a; 服务器接收多个client连接请求后&#xff0c;统一交由Reactor处理&#xff0c;其…

Qt—QPainter基本图形绘制详解

QPainter描述1、QPainter 类在小部件和其他绘制设备上执行低级绘制。2、QPainter 提供了高度优化的功能来完成大多数图形GUI程序所需的工作。它可以画从简单的线条到复杂的形状。它还可以绘制对齐的文本和像素图。QPainter 可以对继承 QPaintDevice 类的任何对象进行操作。3、Q…

【追光者】2022年终总结,又是一个开始,新的挑战。愿你历尽千帆,归来仍是少年。

本文为我原创&#xff0c;未经授权&#xff0c;禁止转载&#xff0c;本文首发于 CSND博客。 这几天&#xff0c;前前后后&#xff0c;断断续续&#xff0c;一边写博客&#xff0c;一边学习&#xff0c;一边回顾我的2022&#xff0c;打磨了好几天&#xff0c;尽管还是有好多想说…

指针进阶之函数指针和函数指针数组

文章目录一、函数指针1.简单介绍2.回忆函数3.函数地址4.函数指针5.案例&#xff08;1&#xff09;案例一&#xff08;2&#xff09;案例二&#xff08;3&#xff09;案例三&#xff08;4&#xff09;案例四代码1代码2误区6.补充二、函数指针数组1.定义2.补充3.案例&#xff08;…

剑指offer----C语言版----第十二天

目录 打印从1到最大的n位数 1.1 题目描述 1.2 Leetcode上的解题思路 1.3 考虑大数的问题 1.3.1 使用字符串模拟数字的加法 1.3.2 使用全排 打印从1到最大的n位数 原题链接&#xff1a;剑指 Offer 17. 打印从1到最大的n位数 - 力扣&#xff08;LeetCode&#xff09;1.1 题…

算法刷题打卡第58天:删除排序链表中的重复元素

删除排序链表中的重复元素 难度&#xff1a;简单 给定一个已排序的链表的头 head &#xff0c;删除所有重复的元素&#xff0c;使每个元素只出现一次。返回已排序的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,1,2] 输出&#xff1a;[1,2]示例 2&#xff1a; 输入…

Cesiumlab对人工模型、建筑矢量面和BIM模型的处理参数设置 CesiumLab系列教程

CesiumLab中将人工模型&#xff08;fbx、obj&#xff09;、建筑矢量面&#xff08;shp&#xff09;和BIM模型&#xff08;clm&#xff09;的处理都集中在一起&#xff0c;统一使用通用模型处理。 输入文件部分&#xff0c;加载文件在这里不在赘述&#xff0c;输入了文件后&…

陪诊系统搭建,陪诊平台应当具备什么功能?

随着近些年来市场的变化&#xff0c;陪诊服务也在慢慢的受到人们的关注&#xff0c;自从有了陪诊系统之后&#xff0c;帮助了许许多多独立就医不便的人群&#xff0c;给了像是搞不清就诊流程的老年人、家人不方便陪伴的孕妇、残障人士&#xff0c;以及需要陪伴就医的独居人士等…

上海市“专精特新”中小企业和杨浦区“专精特新”中小企业给予5万元和3万元资助

杨浦区“专精特新”中小企业认定一、主管部门杨浦区商务委员会二、政策依据《关于印发<杨浦区“专精特新”中小企业培育工程实施办法>的通知》&#xff08;杨商务委规〔2018〕1号&#xff09;《关于组织推荐2021年度杨浦区“专精特新”中小企业申报(复核)的通知》三、扶持…

【Qt】加载.ui转化的.h头文件显示窗体

【Qt】加载.ui转化的.h头文件显示窗体1、背景2、实例3、验证1、背景 将.ui文件转化为.h头文件参考如下博客&#xff1a; 【Qt】将QtDesigner生成的.ui文件转化为.h头文件 https://jn10010537.blog.csdn.net/article/details/128589666其中生成的ui_widget.h头文件内容如下&am…

TensorFlow之超级参数调优

Keras技术框架提供工具类库&#xff0c;用于对TensorFlow程序相关的超级参数进行调优&#xff0c;为机器学习选择正确的超级参数集合的过程被称之为超级参数调优。 超级参数是指用于治理一个机器学习模型的训练过程及其拓扑结构的变量&#xff0c;这些变量在整个训练过程中保持…

尚医通-项目启动过程

1.先启动Redis&#xff1a; redis-server redis.conf & 2.启动docker&#xff1a; systemctl start docker 3.进入mongo容器&#xff1a; docker exec -it mymongo /bin/bash 4.使用MongoDB客户端进行操作 mongo 5.启动nginx&#xff1a;cmd 输入命令nginx 前期使…

【Kotlin】空安全 ③ ( 手动空安全管理 | 非空断言操作符 !! | 使用 if 语句判空 )

文章目录一、非空断言操作符 !!二、使用 if 语句判空一、非空断言操作符 !! Kotlin 中的 可空类型 变量 , 在运行时 可以选择 不启用 安全调用 操作 , 在调用 可空类型 变量 成员 与 方法 时 , 使用 非空断言操作符 !! , 如果 可空类型 变量为 空 , 则 直接抛出 空指针异常 K…

部署k8s集群

环境准备准备三台虚拟机&#xff0c;建议最小硬件配置&#xff1a;2核CPU、2G内存、20G硬盘 &#xff0c;可以访问外网&#xff0c;&#x1f4a1;ps&#xff1a;以下命令在三台虚拟机上都要执行一遍&#xff0c;直到kubeadm init设置虚拟机hostname sudo hostnamectl set-hostn…