Android深入理解权限管理系统---AppOpsService服务

1,118 阅读14分钟

用心坚持输出易读、有趣、有深度、高质量、体系化的技术文章,技术文章也可以有温度。

前言

本文采用对话的方式,人物分别是小昱大牛小昱是一个Android新手,他的理想是能进入大厂,进入大厂后努力赚大钱,争取买房娶媳妇。而为了能进入大厂,它利用工作之余努力学习Android知识。而大牛是一个精通Android各种知识、具有丰富开发经验的老手。小昱和大牛曾经是同事,因此小昱在学习Android知识的路上遇到不会的问题会向大牛请教,那就跟随小昱和大牛的脚步来一起学习Android知识吧。

在阅读本篇之前,建议先阅读下列文章:

Android深入理解权限管理系统---权限管理系统全貌

Android深入理解权限管理系统---PermissionManagerService服务

本文摘要

本文是权限管理系统的第三篇文章。通过本文您将了解到AppOpsService服务是啥它的作用是啥它都提供了哪些功能。(文中代码基于Android13)

本文大纲

1. AppOpsService服务为何物

2. 如何使用AppOpsService服务的功能

3. 总结

1. AppOpsService服务

小昱最近正在研究AppOpsService服务相关的源码,但是研究了一段时间后发现对该服务的作用还是一知半解,并且还存在很多的疑惑点,遂向大牛来请教。

小昱:“大牛啊,我正在研究AppOpsService服务相关的源码,当然刚开始研究我不会一头扎进去去扣各个细节,我是选择了先来了解该类的作用是啥,只有知道了它的作用、它做的事情,才好去再往下一步进行。于是我去看了该类的注释,但是发现越看越头大。”

“注释里提到AppOpsService类具有访问控制操作记录的功能,而在介绍访问控制的时候又提到了权限控制,我就懵逼了,我记得PermissionManagerService服务它是负责权限相关的各种功能的,那AppOpsService服务所做的权限控制到底又是啥子嘛?这个问题困扰我好几天了,请大牛帮帮忙。”

大牛:“AppOpsService其中AppOpsApplication Operations单词的缩写,翻译为中文就是应用操作服务,它也像PackageManagerServicePermissionManagerService一样也是一个binder服务。”

小昱:“不好意思大牛,App Ops (应用操作)指的是啥?没明白。”

“sorry,这个很重要的事情忘记介绍了,App Ops其中的操作是指App使用一些系统资源或者访问别的App的私有数据的操作,比如某个App打开相机、开启录音、打开定位、开启画中画、访问通讯录数据等这些操作就叫App Ops。也就是说只有规定的一些App Ops才会被AppOpsService服务管理,而这些规定的App Ops都定义在AppOpsManager类 (关于该类会在后面介绍),该类总共定义了121App Ops,并且是没有扩展接口的,也就是说其他App不能定义自己的App Ops,系统定义了哪些App Ops就有且只有这些,我截取一小部分代码,如下”

//AppOpsManager类

//定位相关的操作
public static final int OP_COARSE_LOCATION = AppProtoEnums.APP_OP_COARSE_LOCATION;
public static final int OP_FINE_LOCATION = AppProtoEnums.APP_OP_FINE_LOCATION;
public static final int OP_GPS = AppProtoEnums.APP_OP_GPS;
//振动操作
public static final int OP_VIBRATE = AppProtoEnums.APP_OP_VIBRATE;
//读取联系人操作
public static final int OP_READ_CONTACTS = AppProtoEnums.APP_OP_READ_CONTACTS;
//写入联系人操作
public static final int OP_WRITE_CONTACTS = AppProtoEnums.APP_OP_WRITE_CONTACTS;

省略其他操作······

大牛:“就像PermissionManagerService服务一样会把所有App声明的权限所有App使用的权限管理起来。而AppOpsService服务也同样会把所有App的Ops管理起来AppOpsService服务有两个主要功能访问控制记录操作,那我们就依次来介绍下它们。”

1.1 访问控制

先来看一张图

image

图解
  1. App操作(Op)某个资源,该操作的最终执行者是该资源对应的管理者,比如某App开启录音或者打开照相机都属于操作一个资源,而该App是不可能打开录音或者相机的,它只是向录音或者相机的管理者发出一个命令 (录音或者相机的管理者一般都是一个单独的进程)
  2. 资源的管理者收到相应的命令后,它需要到AppOpsService服务验证该App是否有执行该操作的权利
  3. AppOpsService服务验证后,会把验证结果返回给资源管理者,资源管理者根据验证结果再决定是否可以执行该操作

上图中的步骤2步骤3就是AppOpsService服务访问控制的功能体现,用一句话总结就是App在操作某个资源时,资源管理者需要到AppOpsService服务来验证该App是否有执行该操作的权利,AppOpsService服务会把验证结果返回给资源管理者

大牛:“访问控制其实就是AppOpsService服务对于AppOpsManager定义的这些App Ops进行验证,并且把结果返回给调用者。小昱,关于访问控制不知道你是否清楚了。”

小昱:“我明白了,那访问控制权限控制又是啥子呢?”

1.1.1 权限控制

大牛:“同样,解答这个问题,我也画了一幅图,请看下图。”

image

图解
  1. App操作(Op)某个资源,该操作的最终执行者是该资源对应的管理者
  2. 资源的管理者收到相应的命令后,它需要到PermissionManagerService服务验证该App是否被用户授予了相应权限,并把结果返回给资源管理者
  3. 资源管理者拿到结果,若相应权限被用户拒绝了,则不会执行任何操作,并且有可能还会抛出异常,导致App崩溃;若用户授予了相应权限,则再次对相应权限和App到AppOpsService服务进行验证
  4. AppOpsService服务验证后,会把验证结果返回给资源管理者,资源管理者根据验证结果再决定是否可以执行该操作

上图中的步骤2步骤3步骤4就是权限控制的体现,其中的权限指的是系统声明的运行时权限,运行时权限是危险权限,只有在App运行期间需要用户来决定是否授予/拒绝。

结合上图,权限控制用一句话概括就是App在操作某个资源时,资源管理者需要先到PermissionManagerService服务来验证该App是否被用户授予了相应权限,若授予了则再次对相应权限和该App到AppOpsService服务来验证,AppOpsService服务会把验证结果返回给资源管理者

大牛突然压重了声音说:“要千万注意的是,并不是所有的系统声明的运行时权限都需要经过上面的步骤,还记得在AppOpsManager类中定义了121App Ops吧,而大部分的App Ops是对应相应的权限的,当然也有App Ops是没有对应权限的。也就是说只有在AppOpsManager类中有对应App Op的权限才会执行上面步骤。凡是不在AppOpsManager中指定的权限,只需要经过PermissionManagerService服务验证即可,同样我也截取了一部分代码,如下。”

//AppOpsManager类

//sOpPerms存储了Op对应的权限,如果某Op不存在对应的权限,则值为null
private static String[] sOpPerms = new String[] {
            android.Manifest.permission.ACCESS_COARSE_LOCATION,
            android.Manifest.permission.ACCESS_FINE_LOCATION,
            null, //该op操作没有相应的权限,所以值为null
            android.Manifest.permission.VIBRATE,
            android.Manifest.permission.READ_CONTACTS,
            android.Manifest.permission.WRITE_CONTACTS,
            android.Manifest.permission.READ_CALL_LOG,
            android.Manifest.permission.WRITE_CALL_LOG,
            android.Manifest.permission.READ_CALENDAR,
            android.Manifest.permission.WRITE_CALENDAR,
            android.Manifest.permission.ACCESS_WIFI_STATE,
            android.Manifest.permission.POST_NOTIFICATIONS,
            null, // neighboring cells shares the coarse location perm
            省略其他权限······
        }

小昱:“我大概明白了,那我就有个疑问了,PermissionManagerService服务已经对权限验证了,为啥还需要AppOpsService再次对权限进行验证呢?”

大牛:“要解答这个问题先来聊下权限的状态吧,权限是有授予拒绝两种状态一说的,而对于一些权限来说授予状态又被分为前台授予授予,前台授予就是指该权限被授予后,App操作该权限包含的资源时,只能在App处于前台。”

小昱:“稍等啊大牛,关于前台授予我还是有些模糊,麻烦举个例子吧。”

大牛:“好的,比如某App需要开启录音进行声音的录制,该App声明了RECORD_AUDIO权限,并且用户授予了该权限。假如这时候该App退到了后台,因为用户已经授予了该权限,该App在用户完全不知情的情况下偷偷的录制用户的谈话内容,你想想这是多么可怕的事情啊。对于录音、拍照、定位等这类权限都是具有前台授予状态的。”

小昱:“大牛,你这么一说确实是一件恐怖的事情啊,难道AppOpsService服务解决了此事情?”

大牛:“你说的没错是这样的,AppOpsService服务会针对具有前台授予状态的权限再次结合App的前后台状态进行验证,若App这时候处于后台,则会给出MODE_IGNORED值,告知该权限没有被授予,相应资源不能被操作;若App这时候处于前台,则会给出MODE_ALLOWED值,告知该权限被授予了,相应资源能被操作。”

小昱:“哦,那我明白了,正如上面录音的例子,假如使用录音的App处于后台并且想偷偷的开启录音,那录音资源的管理者对RECORD_AUDIO权限去AppOpsService服务进行验证时,AppOpsService服务会告知MODE_IGNORED值,录音资源的管理者也就不会开启录音了。是这样的逻辑吧。”

大牛:“你说的相当正确,那我在介绍记录操作功能吧。”

1.2 记录操作

大牛:“AppOpsService服务记录操作功能非常容易理解,就是把App的操作信息记录下来,那来看下操作信息都有哪些,如下”

  1. 执行该操作的App,这里使用App的uid包名来指明是哪个App,其中uid是App的appid
  2. 该操作是否被执行,被执行则标记为Access,被拒绝则标记为Reject
  3. 该操作发生时间
  4. 该操作的持续时间 (只有长时间操作才有此记录,长时间操作比如录音、拍照这类操作,持续的时间长)

为了有一个直观的感受,请看如下例子:

//u0a112是该App的uid的字符串形式
Uid u0a112:
    ······
    //该App对应的包名
    Package com.example.myapplication2:
      //RECORD_AUDIO操作,其中allow代表允许该操作
      RECORD_AUDIO (allow): 
        null=[
          Access: [top-s] 2024-10-19 21:04:39.605 (-12s891ms)
          //Reject代表 该操作被拒绝了,记录了拒绝时间
          Reject: [top-s]2024-10-18 17:09:21.207 (-1d3h55m31s289ms)
          //Access代表 代表该操作是允许的,14:45:05.191 代表该操作的起始时间,而duration代表持续时间
          Access: [cch-s] 2024-10-18 14:45:05.191 (-1d6h19m47s305ms) duration=+717ms
          Reject: [cch-s]2024-10-18 20:13:36.768 (-1d0h51m15s728ms)
        ]

小昱:“那记录操作信息有啥用处呢?”

大牛:“比如在应用的详情界面可以展示某个权限的操作信息,这样可以告知用户App都做了哪些敏感的操作,如下图片”

大牛:“关于AppOpsService服务的记录操作就介绍到这,还有一个很关键的点,并不是所有的操作都会被记录下来,要不要把某个操作记录下来完全在于使用AppOpsService的哪个接口。”

“小昱,关于AppOpsService服务介绍了这么多,我觉得有必要小结下,温故而知新吗?”

1.3 小结

AppOpsService服务是位于systemserver进程,AppOpsApplication Operations的缩写,因此AppOpsService可以翻译为App操作服务,它像ActivityManagerService服务一样也是一个binder服务。

它的AppOpsManager类中定义了121App Op,只有App操作的资源是属于这121个App Op时,该资源的管理者才会去AppOpsService服务进行验证,资源管理者依据验证结果做出相应的处理,如果验证结果是MODE_ALLOWED,则代表App可以操作该资源;否则不可以。

AppOpsService服务也是对PermissionManagerService服务的补充,PermissionManagerService服务只是验证权限有没有被授予,而AppOpsService服务在验证权限的时候,若权限状态是前台授予,则会结合App的前后台状态给出一个验证结果,如果App处于前台,则会给出MODE_ALLOWED的结果,代表该App可以进行某个操作;否则给出非MODE_ALLOWED结果。AppOpsManager类中定义了App Op对应的权限,如果要验证的权限在AppOpsManager类中能找到对应的App Op,则验证该权限的步骤如下:

  1. PermissionManagerService服务验证该权限是否授予了对应App,如果拒绝了,则直接返回;如果授予了,则进行下一步验证
  2. AppOpsService服务对权限和App再次进行验证

如果要验证的权限在AppOpsManager类中不能找到对应的App Op,则只需要经过PermissionManagerService服务验证即可。

当然AppOpsService服务还可以根据把App的操作信息记录下来,这样就可以做很多事情,比如给用户展示哪些敏感操作在什么时间执行的,执行了多久等。

2. 如何使用AppOpsService服务的功能

小昱:“大牛我已经对AppOpsService服务的功能完全了解了,那在帮我捋捋该如何使用它提供的功能吧。”

大牛:“好的,还记得上面一直提到的一个类AppOpsManager吗?它的作用类似于ActivityManagerPackageManager这些类,因为AppOpsService服务是一个binder服务,因此通过AppOpsManager类就可以通过binder通信来调用AppOpsService服务提供的功能,要想使用AppOpsService服务的相关功能,那依次来介绍AppOpsManager中的四中类型的方法吧。”

checkOp

checkOp类型的方法的作用是验证某个App的某个Op (操作)是否被允许,这个方法很简单就不细说了。

noteOp

noteOp类型的方法的作用不仅具有验证某个App的某个Op (操作)是否被允许,同时还会把该操作记录下来。

startOp 和 finishOp

这两个类型的方法是成对使用的,该方法是针对长时操作来使用的,比如上面一直提到的录音,在开启录音的时候会使用startOp方法,该方法主要是验证某个App的某个Op (操作)是否被允许,同时还会把该操作记录下来。当录音结束的时候,会调用finishOp方法,该方法会停止记录。

小结

大牛:“小昱,我觉得有必要说一下,其实关于以上方法的使用没必要关心,主要原因如下:”

  1. 首先因为AppOpsManager类中已经定义了121App Op,而其他App是根本不可能把自己定义的App Op加入到里面的
  2. 其次是App可以声明权限,但是声明的权限也不可能加入到AppOpsManager对应的App Op中,因为AppOpsManager中已经定好了只有规定的权限才有对应的App Op
  3. 最后是每个App Op都已经在系统代码里被资源管理者校验了,不需要App开发者写相应代码了,比如开启录音,录音的管理者已经间接调用了startOp相关方法对该App是否有执行权限进行了检查

3. 总结

关于AppOpsService服务就介绍到此,谢谢大家。

欢迎关注我的公众号牛晓伟(搜索或者点击牛晓伟链接)