Android system实战 — Android R(11) 第三方apk权限

0. 前言

  最近在调试时遇到了第三方apk申请运行时权限,以及signature级别 install 权限不允许赋予给第三方apk,虽然这是Android系统安全性的一种体现,但在某些情况下,确实是有需求去放开权限,使app能使用更方便,毕竟让用户允许权限在一定程度上来说并不是一件容易的事情。

1. 源码实现

涉及路径:在Android R上权限赋予主要由frameworks\base\services\core\java\com\android\server\pm\permission\PermissionManagerService.java管理

1.1 主要函数

PermissionManagerService中主要负责检查权限及赋予权限的函数为restorePermissionState

    /**
     * Restore the permission state for a package.
     *
     * <ul>
     *     <li>During boot the state gets restored from the disk</li>
     *     <li>During app update the state gets restored from the last version of the app</li>
     * </ul>
     *
     * <p>This restores the permission state for all users.
     *
     * @param pkg the package the permissions belong to
     * @param replace if the package is getting replaced (this might change the requested
     *                permissions of this package)
     * @param packageOfInterest If this is the name of {@code pkg} add extra logging
     * @param callback Result call back
     */
    private void restorePermissionState(@NonNull AndroidPackage pkg, boolean replace,
            @Nullable String packageOfInterest, @Nullable PermissionCallback callback) {
        // IMPORTANT: There are two types of permissions: install and runtime.
        // Install time permissions are granted when the app is installed to
        // all device users and users added in the future. Runtime permissions
        // are granted at runtime explicitly to specific users. Normal and signature
        // protected permissions are install time permissions. Dangerous permissions
        // are install permissions if the app's target SDK is Lollipop MR1 or older,
        // otherwise they are runtime permissions. This function does not manage
        // runtime permissions except for the case an app targeting Lollipop MR1
        // being upgraded to target a newer SDK, in which case dangerous permissions
        // are transformed from install time to runtime ones.

        final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
                pkg.getPackageName());
        if (ps == null) {
            return;
        }

        final PermissionsState permissionsState = ps.getPermissionsState();

        final int[] userIds = getAllUserIds();

        boolean runtimePermissionsRevoked = false;
        int[] updatedUserIds = EMPTY_INT_ARRAY;

        for (int userId : userIds) {
            if (permissionsState.isMissing(userId)) {
                Collection<String> requestedPermissions;
                int targetSdkVersion;
                if (!ps.isSharedUser()) {
                    requestedPermissions = pkg.getRequestedPermissions();
                    targetSdkVersion = pkg.getTargetSdkVersion();
                } else {
                    requestedPermissions = new ArraySet<>();
                    targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
                    List<AndroidPackage> packages = ps.getSharedUser().getPackages();
                    int packagesSize = packages.size();
                    for (int i = 0; i < packagesSize; i++) {
                        AndroidPackage sharedUserPackage = packages.get(i);
                        requestedPermissions.addAll(sharedUserPackage.getRequestedPermissions());
                        targetSdkVersion = Math.min(targetSdkVersion,
                                sharedUserPackage.getTargetSdkVersion());
                    }
                }

                for (String permissionName : requestedPermissions) {
                    BasePermission permission = mSettings.getPermission(permissionName);
                    if (permission == null) {
                        continue;
                    }
                    if (Objects.equals(permission.getSourcePackageName(), PLATFORM_PACKAGE_NAME)
                            && permission.isRuntime() && !permission.isRemoved()) {
                        if (permission.isHardOrSoftRestricted()
                                || permission.isImmutablyRestricted()) {
                            permissionsState.updatePermissionFlags(permission, userId,
                                    FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT,
                                    FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT);
                        }
                        if (targetSdkVersion < Build.VERSION_CODES.M) {
                            permissionsState.updatePermissionFlags(permission, userId,
                                    PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED
                                            | PackageManager.FLAG_PERMISSION_REVOKED_COMPAT,
                                    PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED
                                            | PackageManager.FLAG_PERMISSION_REVOKED_COMPAT);
                            permissionsState.grantRuntimePermission(permission, userId);
                        }
                    }
                }

                permissionsState.setMissing(false, userId);
                updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
            }
        }

        PermissionsState origPermissions = permissionsState;

        boolean changedInstallPermission = false;

        if (replace) {
            ps.setInstallPermissionsFixed(false);
            if (!ps.isSharedUser()) {
                origPermissions = new PermissionsState(permissionsState);
                permissionsState.reset();
            } else {
                // We need to know only about runtime permission changes since the
                // calling code always writes the install permissions state but
                // the runtime ones are written only if changed. The only cases of
                // changed runtime permissions here are promotion of an install to
                // runtime and revocation of a runtime from a shared user.
                synchronized (mLock) {
                    updatedUserIds = revokeUnusedSharedUserPermissionsLocked(
                            ps.getSharedUser(), userIds);
                    if (!ArrayUtils.isEmpty(updatedUserIds)) {
                        runtimePermissionsRevoked = true;
                    }
                }
            }
        }

        permissionsState.setGlobalGids(mGlobalGids);

        synchronized (mLock) {
            ArraySet<String> newImplicitPermissions = new ArraySet<>();

            final int N = pkg.getRequestedPermissions().size();
            for (int i = 0; i < N; i++) {
                final String permName = pkg.getRequestedPermissions().get(i);
                final String friendlyName = pkg.getPackageName() + "(" + pkg.getUid() + ")";
                final BasePermission bp = mSettings.getPermissionLocked(permName);
                final boolean appSupportsRuntimePermissions =
                        pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M;
                String upgradedActivityRecognitionPermission = null;
                if (DEBUG_INSTALL && bp != null) {
                    Log.i(TAG, "Package " + friendlyName
                            + " checking " + permName + ": " + bp);
                }

                if (bp == null || getSourcePackageSetting(bp) == null) {
                    if (packageOfInterest == null || packageOfInterest.equals(
                            pkg.getPackageName())) {
                        if (DEBUG_PERMISSIONS) {
                            Slog.i(TAG, "Unknown permission " + permName
                                    + " in package " + friendlyName);
                        }
                    }
                    continue;
                }

                // Cache newImplicitPermissions before modifing permissionsState as for the shared
                // uids the original and new state are the same object
                if (!origPermissions.hasRequestedPermission(permName)
                        && (pkg.getImplicitPermissions().contains(permName)
                                || (permName.equals(Manifest.permission.ACTIVITY_RECOGNITION)))) {
                    if (pkg.getImplicitPermissions().contains(permName)) {
                        // If permName is an implicit permission, try to auto-grant
                        newImplicitPermissions.add(permName);

                        if (DEBUG_PERMISSIONS) {
                            Slog.i(TAG, permName + " is newly added for " + friendlyName);
                        }
                    } else {
                        // Special case for Activity Recognition permission. Even if AR permission
                        // is not an implicit permission we want to add it to the list (try to
                        // auto-grant it) if the app was installed on a device before AR permission
                        // was split, regardless of if the app now requests the new AR permission
                        // or has updated its target SDK and AR is no longer implicit to it.
                        // This is a compatibility workaround for apps when AR permission was
                        // split in Q.
                        final List<SplitPermissionInfoParcelable> permissionList =
                                getSplitPermissions();
                        int numSplitPerms = permissionList.size();
                        for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
                            SplitPermissionInfoParcelable sp = permissionList.get(splitPermNum);
                            String splitPermName = sp.getSplitPermission();
                            if (sp.getNewPermissions().contains(permName)
                                    && origPermissions.hasInstallPermission(splitPermName)) {
                                upgradedActivityRecognitionPermission = splitPermName;
                                newImplicitPermissions.add(permName);

                                if (DEBUG_PERMISSIONS) {
                                    Slog.i(TAG, permName + " is newly added for " + friendlyName);
                                }
                                break;
                            }
                        }
                    }
                }

                // TODO(b/140256621): The package instant app method has been removed
                //  as part of work in b/135203078, so this has been commented out in the meantime
                // Limit ephemeral apps to ephemeral allowed permissions.
//                if (/*pkg.isInstantApp()*/ false && !bp.isInstant()) {
//                    if (DEBUG_PERMISSIONS) {
//                        Log.i(TAG, "Denying non-ephemeral permission " + bp.getName()
//                                + " for package " + friendlyName);
//                    }
//                    continue;
//                }

                if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) {
                    if (DEBUG_PERMISSIONS) {
                        Log.i(TAG, "Denying runtime-only permission " + bp.getName()
                                + " for package " + friendlyName);
                    }
                    continue;
                }

                final String perm = bp.getName();
                boolean allowedSig = false;
                int grant = GRANT_DENIED;

				// 检查permission是否特殊,针对不同级别permission赋予不同的grant
                // Keep track of app op permissions.
                if (bp.isAppOp()) {
                    mSettings.addAppOpPackage(perm, pkg.getPackageName());
                }

                if (bp.isNormal()) {
                    // For all apps normal permissions are install time ones.
                    grant = GRANT_INSTALL;
                } else if (bp.isRuntime()) {
                    if (origPermissions.hasInstallPermission(bp.getName())
                            || upgradedActivityRecognitionPermission != null) {
                        // Before Q we represented some runtime permissions as install permissions,
                        // in Q we cannot do this anymore. Hence upgrade them all.
                        grant = GRANT_UPGRADE;
                    } else {
                        // For modern apps keep runtime permissions unchanged.
                        grant = GRANT_RUNTIME;
                    }
                } else if (bp.isSignature()) {
                    // For all apps signature permissions are install time ones.
                    allowedSig = grantSignaturePermission(perm, pkg, ps, bp, origPermissions);
                    if (allowedSig) {
                        grant = GRANT_INSTALL;
                    }
                }

                if (DEBUG_PERMISSIONS) {
                    Slog.i(TAG, "Considering granting permission " + perm + " to package "
                            + friendlyName + "grant " + grant);
                }

                 if (grant != GRANT_DENIED) {
                    if (!ps.isSystem() && ps.areInstallPermissionsFixed() && !bp.isRuntime()) {
                        // If this is an existing, non-system package, then
                        // we can't add any new permissions to it. Runtime
                        // permissions can be added any time - they ad dynamic.
                        if (!allowedSig && !origPermissions.hasInstallPermission(perm)) {
                            // Except...  if this is a permission that was added
                            // to the platform (note: need to only do this when
                            // updating the platform).
                            if (!isNewPlatformPermissionForPackage(perm, pkg)) {
                                grant = GRANT_DENIED;
                            }
                        }
                    }

                    switch (grant) {
                        case GRANT_INSTALL: {
                            // Revoke this as runtime permission to handle the case of
                            // a runtime permission being downgraded to an install one.
                            // Also in permission review mode we keep dangerous permissions
                            // for legacy apps
                            for (int userId : userIds) {
                                if (origPermissions.getRuntimePermissionState(
                                        perm, userId) != null) {
                                    // Revoke the runtime permission and clear the flags.
                                    origPermissions.revokeRuntimePermission(bp, userId);
                                    origPermissions.updatePermissionFlags(bp, userId,
                                            PackageManager.MASK_PERMISSION_FLAGS_ALL, 0);
                                    // If we revoked a permission permission, we have to write.
                                    updatedUserIds = ArrayUtils.appendInt(
                                            updatedUserIds, userId);
                                }
                            }
                            // Grant an install permission.
                            if (permissionsState.grantInstallPermission(bp) !=
                                    PERMISSION_OPERATION_FAILURE) {
                                changedInstallPermission = true;
                            }
                        } break;

                        case GRANT_RUNTIME: {
                            boolean hardRestricted = bp.isHardRestricted();
                            boolean softRestricted = bp.isSoftRestricted();

                            for (int userId : userIds) {
                                // If permission policy is not ready we don't deal with restricted
                                // permissions as the policy may whitelist some permissions. Once
                                // the policy is initialized we would re-evaluate permissions.
                                final boolean permissionPolicyInitialized =
                                        mPermissionPolicyInternal != null
                                                && mPermissionPolicyInternal.isInitialized(userId);

                                PermissionState permState = origPermissions
                                        .getRuntimePermissionState(perm, userId);
                                int flags = permState != null ? permState.getFlags() : 0;

                                boolean wasChanged = false;

                                boolean restrictionExempt =
                                        (origPermissions.getPermissionFlags(bp.name, userId)
                                                & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
                                boolean restrictionApplied = (origPermissions.getPermissionFlags(
                                        bp.name, userId) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;

                                if (appSupportsRuntimePermissions) {
                                    // If hard restricted we don't allow holding it
                                    if (permissionPolicyInitialized && hardRestricted) {
                                        if (!restrictionExempt) {
                                            if (permState != null && permState.isGranted()
                                                    && permissionsState.revokeRuntimePermission(
                                                    bp, userId) != PERMISSION_OPERATION_FAILURE) {
                                                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) {
                                        // Regardless if granted set the restriction flag as it
                                        // may affect app treatment based on this permission.
                                        if (!restrictionExempt && !restrictionApplied) {
                                            flags |= FLAG_PERMISSION_APPLY_RESTRICTION;
                                            wasChanged = true;
                                        }
                                    }

                                    // Remove review flag as it is not necessary anymore
                                    if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
                                        flags &= ~FLAG_PERMISSION_REVIEW_REQUIRED;
                                        wasChanged = true;
                                    }

                                    if ((flags & FLAG_PERMISSION_REVOKED_COMPAT) != 0) {
                                        flags &= ~FLAG_PERMISSION_REVOKED_COMPAT;
                                        wasChanged = true;
                                    // Hard restricted permissions cannot be held.
                                    } else if (!permissionPolicyInitialized
                                            || (!hardRestricted || restrictionExempt)) {
                                        if (permState != null && permState.isGranted()) {
                                            if (permissionsState.grantRuntimePermission(bp, userId)
                                                    == PERMISSION_OPERATION_FAILURE) {
                                                wasChanged = true;
                                            }
                                        }
                                    }
                                } else {
                                    if (permState == null) {
                                        // New permission
                                        if (PLATFORM_PACKAGE_NAME.equals(
                                                bp.getSourcePackageName())) {
                                            if (!bp.isRemoved()) {
                                                flags |= FLAG_PERMISSION_REVIEW_REQUIRED
                                                        | FLAG_PERMISSION_REVOKED_COMPAT;
                                                wasChanged = true;
                                            }
                                        }
                                    }

                                    if (!permissionsState.hasRuntimePermission(bp.name, userId)
                                            && permissionsState.grantRuntimePermission(bp, userId)
                                                    != PERMISSION_OPERATION_FAILURE) {
                                        wasChanged = true;
                                    }

                                    // If legacy app always grant the permission but if restricted
                                    // and not exempt take a note a restriction should be applied.
                                    if (permissionPolicyInitialized
                                            && (hardRestricted || softRestricted)
                                                    && !restrictionExempt && !restrictionApplied) {
                                        flags |= FLAG_PERMISSION_APPLY_RESTRICTION;
                                        wasChanged = true;
                                    }
                                }

                                // If unrestricted or restriction exempt, don't apply restriction.
                                if (permissionPolicyInitialized) {
                                    if (!(hardRestricted || softRestricted) || restrictionExempt) {
                                        if (restrictionApplied) {
                                            flags &= ~FLAG_PERMISSION_APPLY_RESTRICTION;
                                            // Dropping restriction on a legacy app implies a review
                                            if (!appSupportsRuntimePermissions) {
                                                flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
                                            }
                                            wasChanged = true;
                                        }
                                    }
                                }

                                if (wasChanged) {
                                    updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
                                }

                                permissionsState.updatePermissionFlags(bp, userId,
                                        MASK_PERMISSION_FLAGS_ALL, flags);
                            }
                        } break;

                        case GRANT_UPGRADE: {
                            // Upgrade from Pre-Q to Q permission model. Make all permissions
                            // runtime
                            PermissionState permState = origPermissions
                                    .getInstallPermissionState(perm);
                            int flags = (permState != null) ? permState.getFlags() : 0;

                            BasePermission bpToRevoke =
                                    upgradedActivityRecognitionPermission == null
                                    ? bp : mSettings.getPermissionLocked(
                                            upgradedActivityRecognitionPermission);
                            // Remove install permission
                            if (origPermissions.revokeInstallPermission(bpToRevoke)
                                    != PERMISSION_OPERATION_FAILURE) {
                                origPermissions.updatePermissionFlags(bpToRevoke,
                                        UserHandle.USER_ALL,
                                        (MASK_PERMISSION_FLAGS_ALL
                                                & ~FLAG_PERMISSION_APPLY_RESTRICTION), 0);
                                changedInstallPermission = true;
                            }

                            boolean hardRestricted = bp.isHardRestricted();
                            boolean softRestricted = bp.isSoftRestricted();

                            for (int userId : userIds) {
                                // If permission policy is not ready we don't deal with restricted
                                // permissions as the policy may whitelist some permissions. Once
                                // the policy is initialized we would re-evaluate permissions.
                                final boolean permissionPolicyInitialized =
                                        mPermissionPolicyInternal != null
                                                && mPermissionPolicyInternal.isInitialized(userId);

                                boolean wasChanged = false;

                                boolean restrictionExempt =
                                        (origPermissions.getPermissionFlags(bp.name, userId)
                                                & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
                                boolean restrictionApplied = (origPermissions.getPermissionFlags(
                                        bp.name, userId) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;

                                if (appSupportsRuntimePermissions) {
                                    // If hard restricted we don't allow holding it
                                    if (permissionPolicyInitialized && hardRestricted) {
                                        if (!restrictionExempt) {
                                            if (permState != null && permState.isGranted()
                                                    && permissionsState.revokeRuntimePermission(
                                                    bp, userId) != PERMISSION_OPERATION_FAILURE) {
                                                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) {
                                        // Regardless if granted set the  restriction flag as it
                                        // may affect app treatment based on this permission.
                                        if (!restrictionExempt && !restrictionApplied) {
                                            flags |= FLAG_PERMISSION_APPLY_RESTRICTION;
                                            wasChanged = true;
                                        }
                                    }

                                    // Remove review flag as it is not necessary anymore
                                    if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
                                        flags &= ~FLAG_PERMISSION_REVIEW_REQUIRED;
                                        wasChanged = true;
                                    }

                                    if ((flags & FLAG_PERMISSION_REVOKED_COMPAT) != 0) {
                                        flags &= ~FLAG_PERMISSION_REVOKED_COMPAT;
                                        wasChanged = true;
                                    // Hard restricted permissions cannot be held.
                                    } else if (!permissionPolicyInitialized ||
                                            (!hardRestricted || restrictionExempt)) {
                                        if (permissionsState.grantRuntimePermission(bp, userId) !=
                                                PERMISSION_OPERATION_FAILURE) {
                                             wasChanged = true;
                                        }
                                    }
                                } else {
                                    if (!permissionsState.hasRuntimePermission(bp.name, userId)
                                            && permissionsState.grantRuntimePermission(bp,
                                                    userId) != PERMISSION_OPERATION_FAILURE) {
                                        flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
                                        wasChanged = true;
                                    }

                                    // If legacy app always grant the permission but if restricted
                                    // and not exempt take a note a restriction should be applied.
                                    if (permissionPolicyInitialized
                                            && (hardRestricted || softRestricted)
                                                    && !restrictionExempt && !restrictionApplied) {
                                        flags |= FLAG_PERMISSION_APPLY_RESTRICTION;
                                        wasChanged = true;
                                    }
                                }

                                // If unrestricted or restriction exempt, don't apply restriction.
                                if (permissionPolicyInitialized) {
                                    if (!(hardRestricted || softRestricted) || restrictionExempt) {
                                        if (restrictionApplied) {
                                            flags &= ~FLAG_PERMISSION_APPLY_RESTRICTION;
                                            // Dropping restriction on a legacy app implies a review
                                            if (!appSupportsRuntimePermissions) {
                                                flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
                                            }
                                            wasChanged = true;
                                        }
                                    }
                                }

                                if (wasChanged) {
                                    updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
                                }

                                permissionsState.updatePermissionFlags(bp, userId,
                                        MASK_PERMISSION_FLAGS_ALL, flags);
                            }
                        } break;

                        default: {
                            if (packageOfInterest == null
                                    || packageOfInterest.equals(pkg.getPackageName())) {
                                if (DEBUG_PERMISSIONS) {
                                    Slog.i(TAG, "Not granting permission " + perm
                                            + " to package " + friendlyName
                                            + " because it was previously installed without");
                                }
                            }
                        } break;
                    }
                } else {
                    if (permissionsState.revokeInstallPermission(bp) !=
                            PERMISSION_OPERATION_FAILURE) {
                        // Also drop the permission flags.
                        permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
                                MASK_PERMISSION_FLAGS_ALL, 0);
                        changedInstallPermission = true;
                        if (DEBUG_PERMISSIONS) {
                            Slog.i(TAG, "Un-granting permission " + perm
                                    + " from package " + friendlyName
                                    + " (protectionLevel=" + bp.getProtectionLevel()
                                    + " flags=0x"
                                    + Integer.toHexString(PackageInfoUtils.appInfoFlags(pkg, ps))
                                    + ")");
                        }
                    } else if (bp.isAppOp()) {
                        // Don't print warning for app op permissions, since it is fine for them
                        // not to be granted, there is a UI for the user to decide.
                        if (DEBUG_PERMISSIONS
                                && (packageOfInterest == null
                                        || packageOfInterest.equals(pkg.getPackageName()))) {
                            Slog.i(TAG, "Not granting permission " + perm
                                    + " to package " + friendlyName
                                    + " (protectionLevel=" + bp.getProtectionLevel()
                                    + " flags=0x"
                                    + Integer.toHexString(PackageInfoUtils.appInfoFlags(pkg, ps))
                                    + ")");
                        }
                    }
                }
            }

            if ((changedInstallPermission || replace) && !ps.areInstallPermissionsFixed() &&
                    !ps.isSystem() || ps.getPkgState().isUpdatedSystemApp()) {
                // This is the first that we have heard about this package, so the
                // permissions we have now selected are fixed until explicitly
                // changed.
                ps.setInstallPermissionsFixed(true);
            }

            updatedUserIds = revokePermissionsNoLongerImplicitLocked(permissionsState, pkg,
                    updatedUserIds);
            updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origPermissions,
                    permissionsState, pkg, newImplicitPermissions, updatedUserIds);
            updatedUserIds = checkIfLegacyStorageOpsNeedToBeUpdated(pkg, replace, updatedUserIds);
        }

        // Persist the runtime permissions state for users with changes. If permissions
        // were revoked because no app in the shared user declares them we have to
        // write synchronously to avoid losing runtime permissions state.
        if (callback != null) {
            callback.onPermissionUpdated(updatedUserIds, runtimePermissionsRevoked);
        }

        for (int userId : updatedUserIds) {
            notifyRuntimePermissionStateChanged(pkg.getPackageName(), userId);
        }
    }

1.2 修改思路和实现

1.2.1 修改思路

  其实我们阅读一下代码可以理解到,Android 会对app申请的权限进行对应分级,比如说signature级权限、dangerous权限仅能赋予系统apk等等的特殊处理。基于这个流程,我们有两种思路:

  1. 所有app申请的权限都作为install 权限赋予给app
  2. 不改变原有流程,模拟用户操作或跳过某些判断

下面我们以跳过runtime permission请求和赋予第三方apksignature级权限为例

1.2.2 方案一

这种方法比较简单粗暴,但是改变了原有流程,目前发现造成某些依赖的so无法找到导致crash的问题,目前暂时未查出原因,但是大部分情况下应该是可以hold住的

diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index a0cae5c..c21ce8f 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -121,6 +121,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+import android.os.SystemProperties;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -2846,7 +2847,11 @@
                             + friendlyName + "grant " + grant);
                 }
 
-                if (grant != GRANT_DENIED) {
+                 String proj_type = SystemProperties.get("sys.proj.type", null);
+                 if ("mobile".equals(proj_type) || "telecom".equals(proj_type) || "unicom".equals(proj_type)) {
+                    grant = GRANT_INSTALL;
+                  }
+                 if (grant != GRANT_DENIED) {
                     if (!ps.isSystem() && ps.areInstallPermissionsFixed() && !bp.isRuntime()) {
                         // If this is an existing, non-system package, then
                         // we can't add any new permissions to it. Runtime

1.2.3 方案二

  1. 跳过runtime permission
    这次的改法就是模拟用户已经允许了runtime permission,修改了flags为USER_SET,并grant 运行权限

    diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
    index c21ce8f..c2edbf4 100644
    --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
    +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
    @@ -2847,10 +2847,6 @@
                                 + friendlyName + "grant " + grant);
                     }
     
    -                 String proj_type = SystemProperties.get("sys.proj.type", null);
    -                 if ("mobile".equals(proj_type) || "telecom".equals(proj_type) || "unicom".equals(proj_type)) {
    -                    grant = GRANT_INSTALL;
    -                  }
                      if (grant != GRANT_DENIED) {
                         if (!ps.isSystem() && ps.areInstallPermissionsFixed() && !bp.isRuntime()) {
                             // If this is an existing, non-system package, then
    @@ -3001,12 +2997,17 @@
                                         }
                                     }
     
    +                                flags |= FLAG_PERMISSION_USER_SET;
                                     if (wasChanged) {
                                         updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
                                     }
     
                                     permissionsState.updatePermissionFlags(bp, userId,
                                             MASK_PERMISSION_FLAGS_ALL, flags);
    +								String proj_type = SystemProperties.get("sys.proj.type", null);
    +                                if ("mobile".equals(proj_type) || "telecom".equals(proj_type) || "unicom".equals(proj_type)) {
    +                                permissionsState.grantRuntimePermission(bp, userId);
    +                                }		
                                 }
                             } break;
     
    
  2. 赋予第三方apk signature权限
    跳过判断是否allowed

    diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
    index 8d2363b..a0cae5c 100644
    --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
    +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
    @@ -103,6 +103,7 @@
     import android.os.UserManagerInternal;
     import android.os.storage.StorageManager;
     import android.os.storage.StorageManagerInternal;
    +import android.os.SystemProperties;
     import android.permission.IOnPermissionsChangeListener;
     import android.permission.IPermissionManager;
     import android.permission.PermissionControllerManager;
    @@ -2835,14 +2836,14 @@
                     } else if (bp.isSignature()) {
                         // For all apps signature permissions are install time ones.
                         allowedSig = grantSignaturePermission(perm, pkg, ps, bp, origPermissions);
    -                    if (allowedSig) {
    +                    if (allowedSig || "mobile".equals(SystemProperties.get("sys.proj.type", null))) {
                             grant = GRANT_INSTALL;
                         }
                     }
     
                     if (DEBUG_PERMISSIONS) {
                         Slog.i(TAG, "Considering granting permission " + perm + " to package "
    -                            + friendlyName);
    +                            + friendlyName + "grant " + grant);
                     }
     
                     if (grant != GRANT_DENIED) {
    
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
非常抱歉,我之前的回答可能有点误导。在 Android 11 中,默认情况下,第三方应用程序无法直接获得 SYSTEM_ALERT_WINDOW 权限。 然而,Android 11 提供了一种新的方法来请求此权限,即通过使用窗口类型为 TYPE_APPLICATION_OVERLAY 或 TYPE_SYSTEM_ALERT 的窗口来创建悬浮窗口。请注意,这种方式仅适用于特定的用例,并且需要用户手动授予权限。 你可以按照以下步骤尝试在 Android 11 上为第三方应用程序开启 SYSTEM_ALERT_WINDOW 权限: 1. 在 AndroidManifest.xml 文件中添加以下权限: ``` <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> ``` 2. 在需要使用悬浮窗口的地方创建一个窗口,并将窗口类型设置为 TYPE_APPLICATION_OVERLAY 或 TYPE_SYSTEM_ALERT。例如: ``` WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY : WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT ); ``` 3. 请求悬浮窗口权限: ``` if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(context)) { Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + context.getPackageName())); startActivityForResult(intent, REQUEST_CODE); } ``` 以上代码示例仅供参考,具体实现取决于你的应用程序需求和架构。请确保遵循 Android 官方文档和最佳实践,以确保应用程序的兼容性和安全性。 请注意,用户需要手动授予悬浮窗口权限。你的应用程序应该处理权限请求结果,并在用户授予权限时使用悬浮窗口功能。 希望这些信息对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ʚ兔子的先森ɞ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值