Android9.0动态运行时权限源码分析及封装改造<一>-----运行时权限名词解释、权限检测源码分析

概述:

我们都知道Google在Android6.0时引入了权限申请机制,也是变革非常大的一块,而如今商用项目中基本上都会涉及到这块,基本上都是使用三方成熟的框架来处理权限的问题,最常用的框为https://github.com/googlesamples/easypermissions,但是!!对于权限这块的知识有没有认真的去研究过呢?反正目前每次想到权限这块我的头还是有点大的,这也就是没有掌握这块原因所致,所以作为一个有追求的码农必须花时间给好好研究一下这块的机理,所以才产生写此篇博客的想法,虽说是烂大街的技术,但是只要是自己没掌握的就得学!

运行时权限名词解释:

先来了解一些跟权限相关的名词,了解它们能够更好的理解接下来要研究的东东,因为分析权限框架源码时会涉及到。

什么是uid、pid?

  • uid:本身是linux权限系统中用以区分用户身份的标识,由于android是单一用户权限系统,uid在android里面又可以理解为应用的标识Id,该Id自安装之日起就被分配,始终如一。
  • pid:顾名思义是进程唯一标识id,用以和远程服务交互。

什么是appId、callerId?

  • appId:可以理解为应用Id,跟uid一样,这是本地应用在远程服务中的叫法。
  • callerId:它是服务请求者的身份Id,可以是本地应用的身份Id,也可以是远程服务在身份标识Id。

危险权限(组):

Android6.0以后将系统权限分为两类:正常权限和危险权限, 对于这俩权限看一下它们俩的区别,借网上的说明:

动态权限处理指的就是对于危险权限的处理,下面来了解一下危险权限都有哪一些:

权限检测源码分析【Android9.0】:

接下来则来分析Android9.0权限框架的源码,分析的入口则是从平常咱们写的申请权限的调用代码开始,先来回忆一下我们是如何来调用的:

package com.permissionarchstudy.test;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

public class MainActivity extends AppCompatActivity {

    private static final int RESULT_CODE_PERMISSIONS_WRITE_EXTERNAL_STORAGE = 100;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {

            } else {
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, RESULT_CODE_PERMISSIONS_WRITE_EXTERNAL_STORAGE);
            }
        }
    }
}

其中申请权限涉及到上面标红的三个api,接下来则按着我们调用的顺序来分析。

checkSelfPermission:

具体来分析一下它:

接下来则点击进去瞅一瞅,我们知道am的具体实现类是ActivityManagerService,所以咱们往它里面继续定位:

继续,发现无法点进去了:

如何解决IDE中跳不到隐藏API的问题?

其实我们手动打开ActivityManager类是能找到这个方法的,如下:

其实将这个hide注解去掉就可以了,问题是我们SDK是从官网下的,去不掉呀,其实网上github上已经有人帮我们整理了,地址:https://github.com/anggrayudi/android-hidden-api:

下面咱们来试一下,下载android-28既可,因为正好咱们分析的就是这个版本:

 

替换到这个位置:

此时IDE刷新之后,就可以正常的跳转啦,如下:

这样看代码就比较方便了,学了个小技巧,流程继续往下:

那啥叫隔离进程呢?在Android中其实是有一个进程的范围的,比如有些应用被拉入黑名单,总之这个进程是没有任何权限的,继续往下:

那又反问一下,啥叫应用自己的权限,我们知道我们可以在manifest中声明自己的权限,比如:

我们知道在manifest中是可以加export属性的:

像上面如果这样声明是不允许被其它调用的,比较好理解,继续:

咱们来瞅一下它的细节:

 

而我们知道它的具体Service则是PackageManagerService,跟进去看一下:

所以,到这个类中来查看进一步的细节:

这个是指访问者或者申请者的应用ID,这个一般是给Google小程序来使用的,国内APP是用不到的,继续:

这里了解一下https://blog.csdn.net/singwhatiwanna/article/details/80490124,其实就是类似于微信小程序:

对于我们应用来说肯定是用不到了,了解一下既可,继续:

正常我们平常开发的应用是不会要配置它的,所以这个条件肯定是进不来的,则看其它条件:

以上条件都没有通过,那很显然此权限木有拥有,则直接返回未授权了:

下面用一张图对上面整个流程进行一个梳理:

shouldShowRequestPermissionRationale:

在上面中如果检测到该权限木有授权,则会往下来执行到它:

 

这是干嘛的呢?看一下官方的解释:

啥意思?继续往下读一段你就明白了,官方举了一个具体的使用它的场景:

哦,这样哟,往里分析一下它的细节:

而它最终会跳到这:

一看就跳到了PackageManagerService了,如下:

回到主流程继续往下分析:

 

其中FLAG_PERMISSION_USER_FIXED它是指用户在权限中明确设置了“不再询问”了,最后就是判断一下是否是这个FLAG,如果是则就需要显示弹窗:

这样的弹窗大概长这样子:

下面也同样来总结一下上面的流程:

原文地址:https://www.cnblogs.com/webor2006/p/12757460.html