权限弹窗点击允许的授权流程

对于appops的理解-CSDN博客

上文知道 grantpermission授权的时候 会同步更新appops的内存 可以通过dumpsys apps | grep xxxx 来查看

在实验的时候,发现appops.xml的持久化文件却没有同步更新,后来继续梳理了一下用户点击权限弹窗到权限到内存中,到最后持久化到磁盘中的流程。

  • PermissionController 是权限 UI/系统应用,用户点击授权后发起 runtime permission 授权请求。
  • PermissionManagerService 修改 Permission 的内存状态,以及异步回调(有延迟)runtime_permission.xml持久化
  • Permission 状态改变后,通过 listener 通知**PermissionPolicyService**。
  • PermissionPolicyService 负责同步 Permission 与 AppOps 的策略状态。
  • Permission 和 AppOps 都不是修改内存后立即写 XML,而是通过异步(有延迟)机制持久化。

零 记忆图

核心:内存状态先改变,磁盘状态后更新。

一 用户点击授权到系统权限更新的流程

1.1 permissioncontroller介绍

permissioncontroller是一个系统应用,也就是你第一次点开应用a,会弹出权限弹窗,一般你点击允许(应用a逻辑会让你继续使用应用a),如果你点击不允许(应用a逻辑会让你不允许)

1.2 简要流程图

permissioncontroller----->packagemanagerservice------->permissionmanagerservice

permissioncontroler(应用进程)到syetem_server(系统进程)

就是调用接口去packagemanagerservice

复制代码
mPM.grantRuntimePermission(packageName,permissionName,user.getIdentifier())

此处经过AIDL 通信 来到packagemanagerservice,

复制代码
public void grantRuntimePermission(String packagename,String permName, final int userId)
    mPermissionManagerService.grantRuntimePermission(packageName,permName,userId)

packagemanagerservice又继续在同进程中来到Permissionmanagerservice

复制代码
public void grantRuntimePermission(String packageName,String permName,final int userId)
    private void grantRuntimePermissionInternal(String permName,String packagename,boolean overridePolicy, int callingUid, final init userId, PermissionCallback callback)

在这里的grantRuntimePermissionInternal这里做了改变内存状态,通知注册回调(写入持久化runtimepermisiom.xml)以及通知appops做相应的变化

二 grantRuntimePermissionInternal

2.1 permissionstate内存状态变化

permissionmanagerservice 维护这一个全局变量permissionstate,在第一时刻接受到内存状态的变化(这里仅做参考 android这里后面版本有改动,大致知道进程内有一个全局变量维护当前进程中的权限状态)

复制代码
final int result = permissionsState.grantRuntimePermission(bp,userId)
......
  public int grantRuntimePermission(BasePermission permission,int userId)
        private int grantPermission(BasePermission,int userId)
            permissionDate.grant(userId)

2.1 通知注册回调 runtimepermission.xml的持久化

这里传入的也是一个延迟写入static final int WRITE_SETTINGS_DELAY = 10*1000; // 10 seconds的

复制代码
callback.onPermissionGranted(uid, userId);
    public void onPermissionGranted(int uid,int userId)
        mPackageManagerInt.writeSetting(true)
        后续回到packagemanagerservice
        public void writeSetting(boolean async)//异步
            void scheduleWriteSettingLocked()
                mHandler.sendEmptyMessageDelayed(WRITE_SETTING,WRITE_SETTINGS_DELAY)

然后在另一个接收线程中

复制代码
public void handleMessage(Message msg)
    void doHandleMessage(Message msg)
        case WRITE_SETTING:
            来到setting.java文件
            void writeLPr()
                void writeAllRuntimePermissionLPr(int userId)
                    来到另一个runtimepermission持久化文件
                    public void writePermissionForUserAsyncLPr(int userId)
                        mHandler.sendMessageDelayed(message,writeDelayMills)
                        这里又是一个异步

在这个线程中

复制代码
public handlerMessage(Message message)
    private void writePermissionsSync(int userId)
        来到runtimepermissionspersistenceimpl.java
        public void writeForUser(xxxx)
         这里就是真正的写入runtimepermission.xml中了

2.2 appops的内存状态改变与持久化

这部分属于是permission的策略,主要是在PermissionPolicyService.java处理的

首先先注册回调

复制代码
permissionManagerInternal.addOnRuntimePermissionStateChangedListener(this::synchronizePackagePermissionsAndAppOpsAsyncForUser);

然后在grantRuntimePermissionInternal走到

复制代码
notifyRuntimePermissionStateChanged(packageName,userId);

接下来开始梳理这个函数,在这里回调给注册到runtimepermissionstatechanged上的listener

复制代码
private void notifyRuntimePermissionStateChanged (@NonNul I Str ing packageName,@UserldInt int userld)
    private void doNotifyRuntimePermissionStateChanged (@NonNulI Str ing packageName, @UserldInt int userld)
        listeners.get(i).onRuntimePermissionStateChanged(packageName,userId);

然后来到frameworks/base/services/core/java/com/android/server/policy/Permission Policyservice,java

复制代码
private void synchronizePackagePermissionsAndAppOpsAsyncForUser (@NonNulI String packageName,@User ldInt int changedUser ld)
    private void synchronizePackagePermissionsAndAppOpsForUser (@NonNulI String packageName,@User ldInt int user ld)
        final PermissionToOpSynchroniser synchroniser = new PermissionToOpSynchroniser(getUserContext(getContext().UserHandle.of(userId));
            synchroniser.addPackage(pkg.packageName);
            synchroniser.syncPackage();
                private void syncPackage();
                    boolean wasSet =setUidModeIgnoredIfNotAllowed(int opCode,int uid,@NonNull String packageName)

然后到frameworks/base/services/core/java/com/android/server/appop/AppOpsService.java中

复制代码
private void setUidMode(int mode,int uid,int mode,@Nullable IAppOpsCallback permissionPolicyCallback)
    scheduleWriteLocaked();
    private void scheduleWlriteLocked ()
        mHandler.postDelayed (mWriteRunner.WRITE_DELAY)
        mWriteScheduled 标志位为true 写完才置为false

这里是一个异步延迟的作用

复制代码
static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;

根据debug模式判断,如果不是DEBUG,是30分钟 也就是 只有每次调用的时候 会在30分钟后将最新的内存中的状态写入到持久化文件中,然后在另一个线程中

那也就是如果这个持久化没有达到时间 没有落盘 这个时候系统意外崩溃 内存中的数据丢失 那这里的持久化就会丢失

复制代码
final Runnable mWriteRunner = new Runnable()
    writeState()
    void writeState()

tip:

  1. Android 系统状态通常存在"内存状态"和"持久化状态"两个层次。

  2. 内存状态变化不代表持久化文件立即变化。

  3. 系统服务为了降低磁盘 I/O,会采用异步/延迟持久化。

  4. Permission 与 AppOps 是两个不同的状态/策略体系,但二者存在同步关系。

  5. 遇到"代码已经执行,但 XML 没变化"的问题时,不能直接判断代码没生效, 要先确认: - 内存状态是否变化 - 是否触发持久化 - 持久化是否异步 - 是否已经真正落盘

相关推荐
AI备忘录1 小时前
(十九)华为华三锐捷迈普思科 交换机链路聚合配置命令(LACP/静态聚合五厂商对照)
运维·服务器·网络·网络协议·tcp/ip·华为
jnrjian1 小时前
Postgres 序列(sequence)的权限
数据库·postgresql
风禾万里1 小时前
【无标题】
数据库
镜舟科技1 小时前
为什么 Text-to-SQL 总是停在 Demo?
数据库·sql·demo·text-to-sql·镜舟科技·mip·语义视图
lucybean011 小时前
抗老化曝气管采购:主流品牌优劣及选型策略深度解析
运维
come112341 小时前
剪映零基础教程
java·linux·运维
人生苦短1281 小时前
Oracle RAC 日常管理+排错命令大全
数据库·oracle
镜舟科技1 小时前
从 DBA 经验到 Agent:镜舟如何构建生产级智能排障体系
数据库·agent·dba·skill·devops agent·mirrorship
瀚高PG实验室1 小时前
HAC 集群主节点状态在starting、running之间频繁切换
运维·数据库·postgresql·瀚高数据库