Android运行时权限Runtime Permission源码分析

news2024/12/19 16:38:34

Runtime Permission源码跟踪

Android 8.1.0

请求权限时弹窗代码

应用使用requestPermissions申请权限时,系统会弹出一个选择窗口,可进行允许。
在这里插入图片描述

源码在packages/apps/PackageInstaller/文件下
GrantPermissionsActivity.java是进行权限分配的弹出窗口,通过GrantPermissionsDefaultViewHandler来控制GrantPermissionsActivity的ui视图,
按钮的点击事件是通过GrantPermissionsViewHandler.ResultListener接口来处理的,GrantPermissionsActivity实现了该接口

public class GrantPermissionsActivity extends OverlayTouchActivity
        implements GrantPermissionsViewHandler.ResultListener {
            mViewHandler = new com.android.packageinstaller.permission.ui.handheld
                    .GrantPermissionsViewHandlerImpl(this, getCallingPackage())
                    .setResultListener(this);
}

GrantPermissionsActivity.java
调用groupState.mGroup.grantRuntimePermissions获取权限,mGroup是AppPermissionGroup.java对象,grantRuntimePermissions实现过程后面会说。

先说下请求权限窗口中的UI,比如显示”要允许xx拔打电话和管理通话嘛“这条文本是
调用GrantPermissionsViewHandlerImpl的updateUi进行界面显示

    private boolean showNextPermissionGroupGrantRequest() {
        final int groupCount = mRequestGrantPermissionGroups.size();

        int currentIndex = 0;
        for (GroupState groupState : mRequestGrantPermissionGroups.values()) {
            if (groupState.mState == GroupState.STATE_UNKNOWN) {
                // 应用名称
                CharSequence appLabel = mAppPermissions.getAppLabel();
                
                // groupState.mGroup.getDescription()是权限对应的中文描述
                // 由AppPermissionGroup.java获取,比如“拨打电话和管理通话”
                // 注意就算请求的是一个子权限,但是获取到的将是子项对应的整个组
                // 比如申请android.permission.CALL_PHONE,允许后,会把它对应的整个电话组
                // 权限都获取到(包含拔打电话、读取通话记录、读取手机状态和身份、修改通话记录)
                Spanned message = Html.fromHtml(getString(R.string.permission_warning_template,
                        appLabel, groupState.mGroup.getDescription()), 0); 
                // Set the permission message as the title so it can be announced.
                setTitle(message);
                
                // 此updateUi会进行UI更新,比如请求权限的应用名,请求的权限对应名称,请求应用的应用图标等
                mViewHandler.updateUi(groupState.mGroup.getName(), groupCount, currentIndex,Icon.createWithResource(resources, icon), message,
                groupState.mGroup.isUserSet());
                //......
            }
        }
    }

mViewHandler对应类是GrantPermissionsViewHandlerImpl.java

mMessageView = (TextView) mCurrentDesc.findViewById(R.id.permission_message);

    private void updateDescription() { // 由updateUi调用
        mIconView.setImageDrawable(mGroupIcon.loadDrawable(mActivity));
        mMessageView.setText(mGroupMessage); // 比如显示“要允许xx拔打电话吗?”
    }

到此请求权限时弹窗代码已结束。

接下来说说设置中的应用权限窗口。

设置中应用权限窗口分析

设置–应用和通知–应用信息—xx应用—权限
在这里插入图片描述
此窗口对应源码为
packages/apps/PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/AppPermissionsFragment.java

// 设置的权限窗口中改变某应用的权限时,会触发此函数
public boolean onPreferenceChange(final Preference preference, Object newValue) {
// 只展试部分关键代码
     // key是权限,比如android.permission.CALL_PHONE
     PermissionInfo permInfo = pm.getPermissionInfo(key, 0);
     
     // AppPermissions mAppPermissions
     final AppPermissionGroup title_group
            = mAppPermissions.getPermissionGroup(permInfo.group);
    if (newValue == Boolean.TRUE) {
        title_group.grantRuntimePermissions(false, filterPermissions); // 取得权限
    } else {
        title_group.revokeRuntimePermissions(false, filterPermissions); // 取消权限
    }
}

上面的mAppPermissions是AppPermissions对象
title_group是AppPermissions.java代码中的mAppPermissions提供

请求权限弹窗与设置中权限UI请求权限都要用到AppPermissionGroup类,调用类中的grantRuntimePermissions函数。

AppPermissionGroup

packages/apps/PackageInstaller/src/com/android/packageinstaller/permission/model/AppPermissions.java

    // 在构造时在loadPermissionGroups初始化AppPermissionGroup数组
    public AppPermissions(Context context, PackageInfo packageInfo, String[] filterPermissions,
            boolean sortGroups, Runnable onErrorCallback) {
        mContext = context;
        mPackageInfo = packageInfo;
        mFilterPermissions = filterPermissions;
        mAppLabel = BidiFormatter.getInstance().unicodeWrap(
                packageInfo.applicationInfo.loadSafeLabel(
                context.getPackageManager()).toString());
        mSortGroups = sortGroups;
        mOnErrorCallback = onErrorCallback;
        loadPermissionGroups(); // 调用addPermissionGroupIfNeeded
    }

    private void addPermissionGroupIfNeeded(String permission) {
        if (getGroupForPermission(permission) != null) {
            return;
        }

        // AppPermissionGroup对应AppPermissionGroup.java
        AppPermissionGroup group = AppPermissionGroup.create(mContext,
                mPackageInfo, permission);
        if (group == null) {
            return;
        }

        mGroups.add(group);
    }

title_group对应AppPermissionGroup.java,AppPermissionGroup.grantRuntimePermissions此函数里面调用的是

private final PackageManager mPackageManager;
 mPackageManager.grantRuntimePermission(mPackageInfo.packageName,permission.getName(), mUserHandle);
 
 // 会跳到PackageManger中, 最终调用到PMS中
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
 ```java
     @Override
    public void grantRuntimePermission(String packageName, String name, final int userId) {
        grantRuntimePermission(packageName, name, userId, false /* Only if not fixed by policy */);
    }

运行时权限获取的权限会通过private void writePermissionsSync(int userId)
更新到此文件中/data/system/users/0/runtime-permissions.xml
某应用,电话组权限未授权时如下

  <pkg name="com.android.sdk23ApiTest.wangyong">
    <item name="android.permission.READ_CALL_LOG" granted="false" flags="1" />
    <item name="android.permission.READ_PHONE_STATE" granted="false" flags="1" />
    <item name="android.permission.CALL_PHONE" granted="false" flags="1" />
    <item name="android.permission.WRITE_CALL_LOG" granted="false" flags="1" />
  </pkg>

允许电话组权限后变成这样

  <pkg name="com.android.sdk23ApiTest.wangyong">
    <item name="android.permission.READ_CALL_LOG" granted="true" flags="0" />
    <item name="android.permission.READ_PHONE_STATE" granted="true" flags="0" />
    <item name="android.permission.CALL_PHONE" granted="true" flags="0" />
    <item name="android.permission.WRITE_CALL_LOG" granted="true" flags="0" />
  </pkg>

Android 6以前的版本是保存在在data/system/packages.xml配置文件中,老版本代码就不分析了。
作者:帅得不敢出门 谢绝转载

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

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

相关文章

分布式之PBFT算法

写在前面 在分布式之拜占庭问题 一文中我们分析了拜占庭问题&#xff0c;并一起看了支持拜占庭容错的口信消息性和签名消息性算法&#xff0c;但是这两种算法都有一个非常严重的问题&#xff0c;就是消息数量太多&#xff0c;通信的成本太大&#xff0c;消息数量复杂度为O(n ^…

CentOS 环境 OpneSIPS 3.1 版本安装及使用

文章目录1. OpenSIPS 源码下载2. 工具准备3. 编译安装4. opensips-cli 工具安装5. 启动 OpenSIPS 实例1. OpenSIPS 源码下载 使用以下命令即可下载 OpenSIPS 的源码&#xff0c;笔者下载的是比较稳定的 3.1 版本&#xff0c;读者有兴趣也可前往 官方传送门 sudo git clone htt…

1个串口用1根线实现多机半双工通信+开机控制电路

功能需求&#xff1a; 主机使用一个串口&#xff0c;与两个从机进行双向通信&#xff0c;主机向从机发送数据&#xff0c;从机能够返回数据&#xff0c;由于结构限制&#xff0c;主机与从机之间只有3根线&#xff08;电源、地、数据线&#xff09;&#xff0c;并且从机上没有设…

【蓝牙mesh】access层(接入层)协议介绍

【蓝牙mesh】access层&#xff08;接入层&#xff09;协议介绍 Access层简介 Access层定义了应用层如何使用upper协议层的接口&#xff0c;它不仅定义了应用层的格式&#xff0c;还定义了应用数据在upper层的加密和解密。当收到下层的数据包时&#xff0c;它会检查数据的netke…

Web前端:选择AngularJS进行Web开发的12大理由!

无论你希望构建本地应用程序、渐进式web应用程序(PWA)&#xff0c;还是开发单页应用程序&#xff0c;每个企业都寻求具有影响力的数字形象&#xff0c;并希望构建交互式、跨平台和动态的web应用程序&#xff0c;以吸引客户。AngularJS&#xff0c;也称为Angular&#xff0c;是一…

李宏毅2023春季机器学习课程

目录2021&2022课程重磅须知我维护的其他项目更新日志课程地址课程资料直链课程作业直链其他优质课程2021&2022课程 CSDN Github 重磅须知 为方便所有网课资料与优质电子书籍的实时更新维护&#xff0c;创建一个在线实时网盘文件夹&#xff1b;   网盘获取方式&#…

C++进阶——继承

C进阶——继承 1.继承的概念及定义 面向对象三大特性&#xff1a;封装、继承、多态。 概念&#xff1a; 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保持原有类特 性的基础上进行扩展&#xff0c;增加功能&#xff0c;这…

MySql数据库环境部署

MySql基础与Sql数据库概述基础环境的建立MYSQL数据库的连接方法MySql的默认数据库数据库端口号数据库概述 数据库&#xff08;DataBase&#xff0c;DB)∶存储在磁带、磁盘、光盘或其他外存介质上、按定结构组织在一起的相关数据的集合。数据库管理系统〈DataBase Management S…

SpringMVC常用注释

1.RequestMapping注释&#xff1a;用来匹配客户端发送的请求&#xff0c;可以在方法上使用&#xff0c;也可以在类上使用。方法&#xff1a;表示用来匹配要处理的请求 类上&#xff1a;表示为当前类的所有方法的请求地址添加一个前置路径&#xff0c;访问的时候必须要添加此路径…

一个.Net Core开源缓存中间件,让你更加简单、方便使用缓存

上次给大家推荐过一个缓存中间件《一个C#开发的非常实用的缓存中间件》&#xff0c;今天再给大家推荐一个缓存中间件&#xff0c;两者功能差不多&#xff0c;都是提供统一接口、多级缓存、分布式缓存、支持多种Provider等。 项目简介 这是一个基于.Net Core开发的缓存中间件&…

Java虚拟机之类加载学习总结

文章目录1 什么是类加载1.1 类加载的应用1.2 类加载过程1.3 类的验证1.4 类初始化顺序2 类加载时机3 类加载器3.1 类加载分类3.2 双亲委派3.3 自定义类加载器3.4 类加载器的命名空间4 打破双亲委派4.1 线程上下文类加载器4.2 自定义类加载器5 类的卸载1 什么是类加载 Java 虚拟…

【工具】JSR-303后端参数校验框架的使用方法及说明

【工具】JSR-303后端参数校验框架的使用方法及说明 文章目录【工具】JSR-303后端参数校验框架的使用方法及说明1. 统一校验需求2. 使用说明2.1 引入依赖2.2 规则说明2.3 使用说明2.4 分组校验2.5 定制校验规则注解1. 统一校验需求 有一句话是这样说的——“前端防君子&#xf…

小知识点:Confluence + mysql 安装流程

流程一、Confluence 配置二、MySQL 配置三、启动一、Confluence 配置 访问下载地址&#xff0c;下载最新安装包 Confluence Server 下载存档 | Atlassian创建环境目录 mkdir -p /xxx/confluence/confluence-home 解压安装包 tar -zxvf atlassian-confluence-7.xx.x.tar.gz -C …

人工智能- windows10环境,配rtx 3060ti显卡,tensorflow-gpu安装

文章目录前言流程方法1.先安装网盘里的anaconda文件&#xff0c;安装后就是python3.8.8环境2.安装vs20193.vs2019安装完毕后开始安装cuda4.安装cudnn5.安装tensorflow-gpu6.测试GPU是否正常识别&#xff0c;tensorflow是否可用前言 最近显卡降价&#xff0c;入手了一块RTX3060…

ROS小车研究笔记:二维SLAM建图简介与源码分析

ROS提供了现成的各类建图算法实现。如果只是应用的话不需要了解详细算法原理&#xff0c;只需要了解其需要的输入输出即可。 1 Gmapping Gmapping使用粒子滤波算法进行建图&#xff0c;在小场景下准确度高&#xff0c;但是在大场地中会导致较大计算量和内存需求 Gmapping需要…

Go语言内存管理详解-学习笔记

1 自动内存管理 1.1 相关概念 Mutator&#xff1a;业务线程&#xff0c;分配新对象&#xff0c;修改对象指向关系Collector&#xff1a;GC线程&#xff0c;找到存活对象&#xff0c;回收死亡对象的内存空间Serial GC&#xff1a;只有一个collector&#xff08;需要暂停&#…

读书笔记//《数据分析之道》

出版时间&#xff1a;2022年 作者曾在互联网大厂做数据分析。从举例可以洞见作者的工作经历。 点评&#xff1a;作者在数据分析领域非常资深&#xff0c;尝试在书中提供一个数据分析工作框架参考。书本内容有点感觉是ppt的集合&#xff0c;辅以案例说明。不过&#xff0c;干货还…

基于ORB-SLAM2+RTAB-MAP+ROS的三维重建设计——环境配置与安装

写下这篇是为了毕设题目《基于深度相机的电缆识别系统》。使用的设备与环境如下&#xff1a;Ubuntu 20.04ROSGazebo仿真运行Kinect 2.0ORB-SLAM2论文地址&#xff1a;https://arxiv.org/abs/1610.06475GitHub&#xff1a;https://github.com/raulmur/ORB_SLAM2一、为什么要选择…

python多线程网络编程

背景 使用过flask框架后&#xff0c;我对request这个全局实例非常感兴趣。它在客户端发起请求后会保存着所有的客户端数据&#xff0c;例如用户上传的表单或者文件等。那么在很多客户端发起请求时&#xff0c;服务器是怎么去区分不同的request对象呢&#xff1f;当查看了大量的…

Android 8请求权限时弹窗BUG

弹窗BUG 应用使用requestPermissions申请权限时&#xff0c;系统会弹出一个选择窗口&#xff0c;可进行允许或拒绝&#xff0c; 此窗口中有一个”不再询问“的选择框&#xff0c; ”拒绝”及“允许”的按钮。 遇到一个Bug,单点击“不再询问”&#xff0c;“允许”这个按钮会变…