1.概述
在14.0的系统rom产品定制化开发中,在6.0以后对于权限的申请,都需要动态申请,所以会在系统首次启动后,在app的首次运行时,
会弹出授权窗口,会让用户手动授予app运行时权限,在由于系统产品开发需要要求默认授予app运行时权限,不需要用户默认授予运行时弹窗,所以需要在首次开机默认授予所有app运行时权限
如图所示:
2.首次开机默认授予app运行时权限(去掉运行时授权弹窗)的解决方案的核心类
frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
frameworks/base/services/core/java/com/android/server/pm/permission/Permission.java
3.首次开机默认授予app运行时权限(去掉运行时授权弹窗)的核心功能分析和实现
首次开机默认授予app运行时权限(去掉运行时授权弹窗)的功能实现中,
在Android 6.0以后由于系统出于对运行安全性的考虑,在app运行中需要申请一些权限的时候,
不会像之前那样什么权限都默认授权,既需要在AndroidManifest.xml需要申请权限,同时对于一些特殊权限需要
在app运行时申请权限,并且会在app每次运行的时候弹出没有授权的授权框来然用户授权,
而在系统中关于权限的管理,就是在PermissionManagerService.java中,它就是负责对系统权限管理的服务
下面对PermissionManagerService.java源码进行分析,看系统具体的怎么授权的,然后
在对app安装的时候进行默认授权来实现功能的要求,接下来分析下PermissionManagerService.java
的相关授权流程来实现功能
3.1 PermissionManagerService.java源码关于权限授权的相关源码分析
在系统中关于app权限的管理,可以看到,PMS只是过渡一下,将uid转化成对应的包信息PackageParser.Package,再转交给PermissionManagerService进行相关权限的管理
所以说,对于系统权限的管理核心处理部分就是在当下类,接下来分析下相关功能
private void updatePermissions(@NonNull String packageName, @Nullable AndroidPackage pkg) {// If the package is being deleted, update the permissions of all the appsfinal int flags =(pkg == null ? UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG: UPDATE_PERMISSIONS_REPLACE_PKG);updatePermissions(packageName, pkg, getVolumeUuidForPackage(pkg), flags, mDefaultPermissionCallback);}private void updatePermissions(final @Nullable String changingPkgName,final @Nullable AndroidPackage changingPkg,final @Nullable String replaceVolumeUuid,@UpdatePermissionFlags int flags,final @Nullable PermissionCallback callback) {boolean permissionTreesSourcePackageChanged = updatePermissionTreeSourcePackage(changingPkgName, changingPkg);boolean permissionSourcePackageChanged = updatePermissionSourcePackage(changingPkgName,changingPkg, callback);if (permissionTreesSourcePackageChanged | permissionSourcePackageChanged) {Slog.i(TAG, "Permission ownership changed. Updating all permissions.");flags |= UPDATE_PERMISSIONS_ALL;}Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "restorePermissionState");// Now update the permissions for all packages.if ((flags & UPDATE_PERMISSIONS_ALL) != 0) {final boolean replaceAll = ((flags & UPDATE_PERMISSIONS_REPLACE_ALL) != 0);mPackageManagerInt.forEachPackage((AndroidPackage pkg) -> {if (pkg == changingPkg) {return;}// Only replace for packages on requested volumefinal String volumeUuid = getVolumeUuidForPackage(pkg);final boolean replace = replaceAll && Objects.equals(replaceVolumeUuid, volumeUuid);restorePermissionState(pkg, replace, changingPkgName, callback,UserHandle.USER_ALL);});}....}
在首次开机默认授予app运行时权限(去掉运行时授权弹窗)的功能实现中,
在上述的PermissionManagerService.java中的相关源码中分析得知,在上述的方法中,在
updatePermissions()方法中,系统开机起来后就会会更新应用的权限,就会调用该方法updatePermissions()
接下来又继续调用updatePermissions(final @Nullable String changingPkgName,
final @Nullable AndroidPackage changingPkg,
final @Nullable String replaceVolumeUuid,
@UpdatePermissionFlags int flags,
final @Nullable PermissionCallback callback) 来负责申请权限,接下来就在这个方法中
继续调用restorePermissionState(pkg, replace, changingPkgName, callback, UserHandle.USER_ALL);
来负责申请权限的相关方法来开机默认给应用授权,接下来分析下相关的restorePermissionState方法
private void restorePermissionState(@NonNull AndroidPackage pkg, boolean replace,@Nullable String packageOfInterest, @Nullable PermissionCallback callback,@UserIdInt int filterUserId) {final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(pkg.getPackageName());if (ps == null) {return;} ....boolean shouldGrantNormalPermission = true;if (bp.isNormal() && !origState.isPermissionGranted(perm)) {if (!ps.isSystem() && userState.areInstallPermissionsFixed(ps.name)) {if (!isNewPlatformPermissionForPackage(perm, pkg)) {shouldGrantNormalPermission = false;}}}if (DEBUG_PERMISSIONS) {Slog.i(TAG, "Considering granting permission " + perm + " to package "+ pkg.getPackageName());}if ((bp.isNormal() && shouldGrantNormalPermission)|| (bp.isSignature()&& (!bp.isPrivileged() || CollectionUtils.contains(isPrivilegedPermissionAllowlisted, permName))&& (CollectionUtils.contains(shouldGrantSignaturePermission,permName)|| (((bp.isPrivileged() && CollectionUtils.contains(shouldGrantPrivilegedPermissionIfWasGranted,permName)) || bp.isDevelopment() || bp.isRole())&& origState.isPermissionGranted(permName))))|| (bp.isInternal()&& (!bp.isPrivileged() || CollectionUtils.contains(isPrivilegedPermissionAllowlisted, permName))&& (CollectionUtils.contains(shouldGrantInternalPermission,permName)|| (((bp.isPrivileged() && CollectionUtils.contains(shouldGrantPrivilegedPermissionIfWasGranted,permName)) || bp.isDevelopment() || bp.isRole())&& origState.isPermissionGranted(permName))))) {// Grant an install permission.if (uidState.grantPermission(bp)) {changedInstallPermission = true;}} else if (bp.isRuntime()) {boolean hardRestricted = bp.isHardRestricted();boolean softRestricted = bp.isSoftRestricted();final boolean permissionPolicyInitialized =isPermissionPolicyInitialized.get(userId);PermissionState origPermState = origState.getPermissionState(perm);int flags = origPermState != null ? origPermState.getFlags() : 0;boolean wasChanged = false;boolean restrictionExempt =(origState.getPermissionFlags(bp.getName())& FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;boolean restrictionApplied = (origState.getPermissionFlags(bp.getName()) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;if (appSupportsRuntimePermissions) {// If hard restricted we don't allow holding itif (permissionPolicyInitialized && hardRestricted) {if (!restrictionExempt) {if (origPermState != null && origPermState.isGranted()&& uidState.revokePermission(bp)) {wasChanged = true;}if (!restrictionApplied) {flags |= FLAG_PERMISSION_APPLY_RESTRICTION;wasChanged = true;}}// If soft restricted we allow holding in a restricted form} else if (permissionPolicyInitialized && softRestricted) {if (!restrictionExempt && !restrictionApplied) {flags |= FLAG_PERMISSION_APPLY_RESTRICTION;wasChanged = true;}}if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {flags &= ~FLAG_PERMISSION_REVIEW_REQUIRED;wasChanged = true;}if ((flags & FLAG_PERMISSION_REVOKED_COMPAT) != 0&& !isPermissionSplitFromNonRuntime(permName,pkg.getTargetSdkVersion())) {flags &= ~FLAG_PERMISSION_REVOKED_COMPAT;wasChanged = true;// Hard restricted permissions cannot be held.} else if (!permissionPolicyInitialized|| (!hardRestricted || restrictionExempt)) {if ((origPermState != null && origPermState.isGranted())|| legacyActivityRecognitionPermission != null) {if (!uidState.grantPermission(bp)) {wasChanged = true;}}}} else {if (origPermState == null) {// New permissionif (PLATFORM_PACKAGE_NAME.equals(bp.getPackageName())) {if (!bp.isRemoved()) {flags |= FLAG_PERMISSION_REVIEW_REQUIRED| FLAG_PERMISSION_REVOKED_COMPAT;wasChanged = true;}}}if (!uidState.isPermissionGranted(bp.getName())&& uidState.grantPermission(bp)) {wasChanged = true;}if (permissionPolicyInitialized&& (hardRestricted || softRestricted)&& !restrictionExempt && !restrictionApplied) {flags |= FLAG_PERMISSION_APPLY_RESTRICTION;wasChanged = true;}}....updatedUserIds = revokePermissionsNoLongerImplicitLocked(uidState, pkg,userId, updatedUserIds);updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origState,uidState, pkg, newImplicitPermissions, userId, updatedUserIds);}}...}
首次开机默认授予app运行时权限(去掉运行时授权弹窗)的功能实现中,
在上述的PermissionManagerServiceImpl.java文件中的相关源码分析得知,在restorePermissionState方法中会首先根据包名遍历每个需要
申请的权限,然后根据权限的类型判断是否是安装权限,还是运行时权限,在6.0以前都是安装权限,在app安装的过程中授予安全权限,
6.0以后就都变成运行时权限在首次运行的过程中弹窗让用户授权,所以如果授予运行时权限,就需要将应用权限设置为安装权限,就是上文中的bp.isNormal() 就代表是安装权限和bp.isRuntime()
就代表是运行时权限,而他们都是Permission.java中的方法,就需要在Permission.java中来实现功能
3.2 Permission.java中关于权限类型的分析和功能实现
首次开机默认授予app运行时权限(去掉运行时授权弹窗)的功能实现中,
Android系统中对于系统权限授权的一个很明显的分界线是Android 6.0(Api=23),在这之前,只需要在AndroidManifest.xml声明应用需要的权限
在对于运行时权限的属性的管理就是统一由Permission.java中来判断是否是运行时权限还是安装权限的,以及特殊权限等等
接下来具体分析下Permission.java中的相关源码
public boolean isNormal() {- return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)- == PermissionInfo.PROTECTION_NORMAL;+ return true;}public boolean isRuntime() {- return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)- == PermissionInfo.PROTECTION_DANGEROUS;+ return false;}
首次开机默认授予app运行时权限(去掉运行时授权弹窗)的功能实现中, 在上述Permission.java中的相关源码分析得知,在这里,Permission.java中在安装授予权限的
时候,会首先判断这个权限的属性是运行时权限还是安装权限等等,在上述的PermissionManagerService.java文件
中的restorePermissionState方法中也分析了相关的权限授权,所以在上述的isNormal()中
就默认返回true,代表是安装权限,在isRuntime()中返回false就是代表不是运行时权限来实现功能