Android M权限管理(续)
来源:互联网 发布:金蝶erp软件二次开发 编辑:程序博客网 时间:2024/06/07 23:57
在Android M权限管理这篇文章里,我大致的介绍了Android的动态权限管理,同时简单梳理了一下权限的检查和申请的流程。
在上篇文章的末尾,我们停在了PackageInstaller这个包的grantRuntimePermission这个方法。在这个方法里我们看到,PackageInstaller也是保存了不少的权限的状态,但真正对权限进行“操作”的还是在PackageManagerService,这部分内容很多,我就单独拿出来写这篇续了。
先贴上grantRuntimePermission的源码:
@Override public void grantRuntimePermission(String packageName, String name, final int userId) { if (!sUserManager.exists(userId)) { Log.e(TAG, "No such user:" + userId); return; } mContext.enforceCallingOrSelfPermission( android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, "grantRuntimePermission"); enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "grantRuntimePermission"); final int uid; final SettingBase sb; synchronized (mPackages) { final PackageParser.Package pkg = mPackages.get(packageName); if (pkg == null) { throw new IllegalArgumentException("Unknown package: " + packageName); } final BasePermission bp = mSettings.mPermissions.get(name); if (bp == null) { throw new IllegalArgumentException("Unknown permission: " + name); } enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(pkg, bp); uid = UserHandle.getUid(userId, pkg.applicationInfo.uid); sb = (SettingBase) pkg.mExtras; if (sb == null) { throw new IllegalArgumentException("Unknown package: " + packageName); } final PermissionsState permissionsState = sb.getPermissionsState(); final int flags = permissionsState.getPermissionFlags(name, userId); if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) { throw new SecurityException("Cannot grant system fixed permission: " + name + " for package: " + packageName); } if (bp.isDevelopment()) { // Development permissions must be handled specially, since they are not // normal runtime permissions. For now they apply to all users. if (permissionsState.grantInstallPermission(bp) != PermissionsState.PERMISSION_OPERATION_FAILURE) { scheduleWriteSettingsLocked(); } return; } final int result = permissionsState.grantRuntimePermission(bp, userId); switch (result) { case PermissionsState.PERMISSION_OPERATION_FAILURE: { return; } case PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: { final int appId = UserHandle.getAppId(pkg.applicationInfo.uid); mHandler.post(new Runnable() { @Override public void run() { killUid(appId, userId, KILL_APP_REASON_GIDS_CHANGED); } }); } break; } mOnPermissionChangeListeners.onPermissionsChanged(uid); // Not critical if that is lost - app has to request again. mSettings.writeRuntimePermissionsForUserLPr(userId, false); } // Only need to do this if user is initialized. Otherwise it's a new user // and there are no processes running as the user yet and there's no need // to make an expensive call to remount processes for the changed permissions. if (READ_EXTERNAL_STORAGE.equals(name) || WRITE_EXTERNAL_STORAGE.equals(name)) { final long token = Binder.clearCallingIdentity(); try { if (sUserManager.isInitialized(userId)) { MountServiceInternal mountServiceInternal = LocalServices.getService( MountServiceInternal.class); mountServiceInternal.onExternalStoragePolicyChanged(uid, packageName); } } finally { Binder.restoreCallingIdentity(token); } } }
在19行,获取了一个Package对象pkg,这个对象中包含了你能想到的一个应用的各种信息,非常详尽。在32行,从pkg中获取了SettingBase对象sb,这个SettingBase中有一个PermissionsState对象,我们最终权限的操作就是调用的PermissionsState的方法,具体在55行。这里我们看到另一个参数bp,这是一个BaseSetting对象,这个对象包含了一项权限的基本信息。对55行做个小翻译就是:赋予userId的应用的bp这个权限以运行时权限。
其实从PermissionsState的名字我们也可以猜出来这个类就是保存的pkg的所有的权限状态,各种操作和它肯定是拖不了关系的。
private int grantPermission(BasePermission permission, int userId) { if (hasPermission(permission.name, userId)) { return PERMISSION_OPERATION_FAILURE; } final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId)); final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS; PermissionData permissionData = ensurePermissionData(permission); if (!permissionData.grant(userId)) { return PERMISSION_OPERATION_FAILURE; } if (hasGids) { final int[] newGids = computeGids(userId); if (oldGids.length != newGids.length) { return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED; } } return PERMISSION_OPERATION_SUCCESS; }
在第9行,调用ensurePermissionData获取一个PermissionData对象。若是第一次对该权限操作,会新建一个PermissionData对象,并存入mPermissions这个Map中。
然后我们就用PermissionData来grant了。
public boolean grant(int userId) { if (!isCompatibleUserId(userId)) { return false; } if (isGranted(userId)) { return false; } PermissionState userState = mUserStates.get(userId); if (userState == null) { userState = new PermissionState(mPerm.name); mUserStates.put(userId, userState); } userState.mGranted = true; return true; }
这里的逻辑挺清楚的,userId不对或者已经有权限,返回失败;若之前没有处理过该权限,先新建一个PermissionState对象,然后将其存入mUserStates中,将mGranted设为true。
走到这里grant的流程就走完了,整理一下:
- PackageManagerService中通过mPackage得到目标pkg ;
- 通过mSettings.mPermissions获取到目标权限bp ;
- 通过pkg得到一个PermissionsState对象permissionsState;
- 使用permissionsState对象来对pkg的bp进行赋予权限的操作;
- 通过ensurePermissionData方法获取一个PermissionData对象pd;
- 使用pd来赋予权限
其实到这里,一直没有看到进行持久化操作。这部分内容在PackageManagerService的grantRuntimePermission的末尾,在上面源码的76行,发现没带上pkg和bp这些参数。继续跟了一下,发现这个方法是异步的写xml,而且是直接更新mPackage所有内容。。。这难道不会有性能问题么。。虽然有异步并且移除旧任务的操作。
至此,运行时权限的内容就分析完了。想想还有安装时,默认权限的赋予没有写,后续看情况再添加把。
大家若看到有不对的地方,希望及时指出,多多交流,我也好及时修正,避免误导他人。
- Android M权限管理(续)
- Android M权限管理
- Android M权限管理
- Android M Permissions 权限管理
- Android M动态权限管理
- Android M 运行时权限管理
- Android M 权限管理拿不到OnRequestPermissionsResult的回调
- Android M Android6.0 权限管理 EasyPermission Demo
- android M权限问题
- Android M 权限
- Android M权限请求
- android M 系统权限
- Android (6.0) M 请求权限
- android M 动态申请权限
- Android M 动态权限获取
- Android M 动态权限获取
- Android M(6.0) 权限解决方案
- Android M(6.0) 权限解决方案
- PDF在线预览
- 苏嵌PCB部分
- 软件测试产物命名规范化
- Storm UI界面参数详说明
- android 实现和手机home键一样的功能。
- Android M权限管理(续)
- hdu 6030 (矩阵快速幂)
- 关于const
- ReactiveCocoa入门教程:第一部分
- const与static归纳总结
- HDU 6024 Building Shops
- TransitionDrawable一个能渐变显示的Drawable
- Spring IOC之通过JAVA代码配置Bean
- PAT 乙级 1034. 有理数四则运算(20)