上文知道 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:
Android 系统状态通常存在"内存状态"和"持久化状态"两个层次。
内存状态变化不代表持久化文件立即变化。
系统服务为了降低磁盘 I/O,会采用异步/延迟持久化。
Permission 与 AppOps 是两个不同的状态/策略体系,但二者存在同步关系。
遇到"代码已经执行,但 XML 没变化"的问题时,不能直接判断代码没生效, 要先确认: - 内存状态是否变化 - 是否触发持久化 - 持久化是否异步 - 是否已经真正落盘