android 权限申请

发布时间 2023-04-11 11:05:38作者: xiaowang_lj

官方文档:请求运行时权限  |  Android 开发者  |  Android Developers 

官方提供的模板使用了三个条件分支来请求应用权限:
  1.checkSelfPermission用来检查应用是否获得 需要请求的权限,如果有权限,直接执行需要的动作;
  2.shouldShowRequestPermissionRationale在用户曾经点击过拒绝这一权限的选项后为true(非“拒绝不再询问”选项),这时系统发现应用没有响应的权限,开发者可以在这一条件分支加上相关说明的界面,向用户指出申请这个权限的必要性,但是还是有必要在界面向用户提供“拒绝”的选项;
  3.当走到最后一个分支,也就意味着应用还没有响应的权限,且用户不曾点击过拒绝这一权限的选项,于是使用requestPermissions唤起对话框申请权限。

    public void requestPermission(String permission){
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
            //已经授权
            Log.e("TAG","已经授权");
        }else if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE)) {
            //拒绝过授权
            Log.e("TAG","拒绝过授权");
            ActivityCompat.requestPermissions(this, new String[]{permission}, 1);
        }
        else {
            //未授权
            Log.e("TAG","未授权");
            ActivityCompat.requestPermissions(this, new String[]{permission}, 1);
        }
    }

源码追踪

检查权限 checkSelfPermission 

checkSelfPermission最终会调用到ActivityManager#checkComponentPermission,并且使得传入的pid和uid参数分别为应用的pid和uid。

 public static int checkSelfPermission(@NonNull Context context, @NonNull String permission) {
        ObjectsCompat.requireNonNull(permission, "permission must be non-null");
        return context.checkPermission(permission, Process.myPid(), Process.myUid());
    }
./frameworks/base/core/java/android/content/Context.java
@CheckResult(suggest="#enforcePermission(String,int,int,String)") @PackageManager.PermissionResult public abstract int checkPermission(@NonNull String permission, int pid, int uid);
frameworks\base\core\java\android\app\ContextImpl.java
@Override
public int checkPermission(String permission, int pid, int uid) { if (permission == null) { throw new IllegalArgumentException("permission is null"); } if (mParams.isRenouncedPermission(permission) && pid == android.os.Process.myPid() && uid == android.os.Process.myUid()) { Log.v(TAG, "Treating renounced permission " + permission + " as denied"); return PERMISSION_DENIED; } return PermissionManager.checkPermission(permission, pid, uid); }

./frameworks/base/core/java/android/permission/PermissionManager.java

 /** @hide */
    public static int checkPermission(@Nullable String permission, int pid, int uid) {
        return sPermissionCache.query(new PermissionQuery(permission, pid, uid));
    }
private static final PropertyInvalidatedCache<PermissionQuery, Integer> sPermissionCache =
            new PropertyInvalidatedCache<PermissionQuery, Integer>(
                    2048, CACHE_KEY_PACKAGE_INFO, "checkPermission") {
                @Override
                protected Integer recompute(PermissionQuery query) {
                    return checkPermissionUncached(query.permission, query.pid, query.uid);
                }
            };
    /* @hide */
    private static int checkPermissionUncached(@Nullable String permission, int pid, int uid) {
        final IActivityManager am = ActivityManager.getService();
        if (am == null) {
            // Well this is super awkward; we somehow don't have an active ActivityManager
            // instance. If we're testing a root or system UID, then they totally have whatever
            // permission this is.
            final int appId = UserHandle.getAppId(uid);
            if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) {
                Slog.w(LOG_TAG, "Missing ActivityManager; assuming " + uid + " holds "
                        + permission);
                return PackageManager.PERMISSION_GRANTED;
            }
            Slog.w(LOG_TAG, "Missing ActivityManager; assuming " + uid + " does not hold "
                    + permission);
            return PackageManager.PERMISSION_DENIED;
        }
        try {
            return am.checkPermission(permission, pid, uid);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

 

frameworks\base\core\java\android\app\IActivityManager.aidl

@UnsupportedAppUsage
    int checkPermission(in String permission, int pid, int uid);

frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java

 @Override
    public int checkPermission(String permission, int pid, int uid) {
        if (permission == null) {
            return PackageManager.PERMISSION_DENIED;
        }
        return checkComponentPermission(permission, pid, uid, -1, true);
    }
    public static int checkComponentPermission(String permission, int pid, int uid,
            int owningUid, boolean exported) {
        if (pid == MY_PID) {
            return PackageManager.PERMISSION_GRANTED;
        }
        // If there is an explicit permission being checked, and this is coming from a process
        // that has been denied access to that permission, then just deny.  Ultimately this may
        // not be quite right -- it means that even if the caller would have access for another
        // reason (such as being the owner of the component it is trying to access), it would still
        // fail.  This also means the system and root uids would be able to deny themselves
        // access to permissions, which...  well okay. ¯\_(ツ)_/¯
        if (permission != null) {
            synchronized (sActiveProcessInfoSelfLocked) {
                ProcessInfo procInfo = sActiveProcessInfoSelfLocked.get(pid);
                if (procInfo != null && procInfo.deniedPermissions != null
                        && procInfo.deniedPermissions.contains(permission)) {
                    return PackageManager.PERMISSION_DENIED;
                }
            }
        }
        return ActivityManager.checkComponentPermission(permission, uid,
                owningUid, exported);
    }

frameworks\base\core\java\android\app\ActivityManager.java

    /** @hide */
    @UnsupportedAppUsage
    public static int checkComponentPermission(String permission, int uid,
            int owningUid, boolean exported) {
        // Root, system server get to do everything.
        final int appId = UserHandle.getAppId(uid);
        if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) {
            return PackageManager.PERMISSION_GRANTED;
        }
        // Isolated processes don't get any permissions.
        if (UserHandle.isIsolated(uid)) {
            return PackageManager.PERMISSION_DENIED;
        }
        // If there is a uid that owns whatever is being accessed, it has
        // blanket access to it regardless of the permissions it requires.
        if (owningUid >= 0 && UserHandle.isSameApp(uid, owningUid)) {
            return PackageManager.PERMISSION_GRANTED;
        }
        // If the target is not exported, then nobody else can get to it.
        if (!exported) {
            /*
            RuntimeException here = new RuntimeException("here");
            here.fillInStackTrace();
            Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid,
                    here);
            */
            return PackageManager.PERMISSION_DENIED;
        }
        if (permission == null) {
            return PackageManager.PERMISSION_GRANTED;
        }
        try {
            return AppGlobals.getPackageManager()
                    .checkUidPermission(permission, uid);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

AM端的判断原则是:
  1.对root和system的uid通过检查;
  2.对isolated的uid不通过检查;
  3.对检查的权限是发起检查者定义的情况直接通过;
  4.对访问不开放(android:exported为false)组件情况不通过;
  5.对检查的权限为null的情况直接通过;
  如果上面5条还不能确认结果的话,交给PMS的checkUidPermission函数再进行判断:

frameworks\base\core\java\android\app\AppGlobals.java

    @UnsupportedAppUsage
    public static IPackageManager getPackageManager() {
        return ActivityThread.getPackageManager();
    }

frameworks\base\core\java\android\content\pm\IPackageManager.aidl

int checkUidPermission(String permName, int uid);

frameworks\base\services\core\java\com\android\server\pm\PackageManagerService.java

@Override
    public int checkUidPermission(String permName, int uid) {
        return mComputer.checkUidPermission(permName, uid);
    }
private final ComputerTracker mComputer = new ComputerTracker(this);
ComputerTracker 是PackageManagerService的内部类
 /**
     * This subclass delegates to methods in a Computer after reference-counting the computer.
     */
    private static class ComputerTracker implements Computer {

/**
* This class records the Computer being used by a thread and the Computer's reference
* count. There is a thread-local copy of this class.
*/
private static class ThreadComputer {


public final int checkUidPermission(String permName, int uid) { ThreadComputer current = snapshot(); try { return current.mComputer.checkUidPermission(permName, uid); } finally { current.release(); } }
// NOTE: Can't remove without a major refactor. Keep around for now.
        public final int checkUidPermission(String permName, int uid) {
            return mPermissionManager.checkUidPermission(uid, permName);
        }

PackageManagerService使用 ThreadLocal 和 锁同步了内部的状态

 // Internal interface for permission manager
    private final PermissionManagerServiceInternal mPermissionManager;

framework/base/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java

//@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
    int checkUidPermission(int uid, @NonNull String permissionName);

frameworks\base\services\core\java\com\android\server\pm\permission\PermissionManagerService.java

    private int checkUidPermission(int uid, String permName) {
        // Not using Objects.requireNonNull() here for compatibility reasons.
        if (permName == null) {
            return PackageManager.PERMISSION_DENIED;
        }
        final int userId = UserHandle.getUserId(uid);
        if (!mUserManagerInt.exists(userId)) {
            return PackageManager.PERMISSION_DENIED;
        }

        final CheckPermissionDelegate checkPermissionDelegate;
        synchronized (mLock) {
            checkPermissionDelegate = mCheckPermissionDelegate;
        }
        if (checkPermissionDelegate == null)  {
            return checkUidPermissionImpl(uid, permName);
        }
        return checkPermissionDelegate.checkUidPermission(uid, permName,
                this::checkUidPermissionImpl);
    }

mCheckPermissionDelegate是一个可嵌入的权限判断实现,由setCheckPermissionDelegateLocked嵌入,如果不为null,则调用嵌入代码的checkUidPermission进行判断。app进行检查的情况下这段嵌入实现为null,所以会调PMS的checkUidPermissionImpl进行判断。

private int checkUidPermissionImpl(int uid, String permName) {
        final AndroidPackage pkg = mPackageManagerInt.getPackage(uid);
        return checkUidPermissionInternal(pkg, uid, permName);
    }
    private int checkUidPermissionInternal(@Nullable AndroidPackage pkg, int uid,
            @NonNull String permissionName) {
        if (pkg != null) {
            final int userId = UserHandle.getUserId(uid);
            return checkPermissionInternal(pkg, false, permissionName, userId);
        }

        synchronized (mLock) {
            if (checkSingleUidPermissionInternalLocked(uid, permissionName)) {
                return PackageManager.PERMISSION_GRANTED;
            }

            final String fullerPermissionName = FULLER_PERMISSION_MAP.get(permissionName);
            if (fullerPermissionName != null
                    && checkSingleUidPermissionInternalLocked(uid, fullerPermissionName)) {
                return PackageManager.PERMISSION_GRANTED;
            }
        }

        return PackageManager.PERMISSION_DENIED;
    }
    private int checkPermissionInternal(@NonNull AndroidPackage pkg, boolean isPackageExplicit,
            @NonNull String permissionName, @UserIdInt int userId) {
        final int callingUid = getCallingUid();
        if (isPackageExplicit || pkg.getSharedUserId() == null) {
            if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
                return PackageManager.PERMISSION_DENIED;
            }
        } else {
            if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
                return PackageManager.PERMISSION_DENIED;
            }
        }

        final int uid = UserHandle.getUid(userId, pkg.getUid());
        final boolean isInstantApp = mPackageManagerInt.getInstantAppPackageName(uid) != null;

        synchronized (mLock) {
            final UidPermissionState uidState = getUidStateLocked(pkg, userId);
            if (uidState == null) {
                Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user "
                        + userId);
                return PackageManager.PERMISSION_DENIED;
            }

            if (checkSinglePermissionInternalLocked(uidState, permissionName, isInstantApp)) {
                return PackageManager.PERMISSION_GRANTED;
            }

            final String fullerPermissionName = FULLER_PERMISSION_MAP.get(permissionName);
            if (fullerPermissionName != null && checkSinglePermissionInternalLocked(uidState,
                    fullerPermissionName, isInstantApp)) {
                return PackageManager.PERMISSION_GRANTED;
            }
        }

        return PackageManager.PERMISSION_DENIED;
    }

PermissionManagerService的判断原则如下:
  1.申请检查者拥有shareuserid且是instant app的情况不通过;
  2.申请检查者的userid在系统中未启动的情况不通过;
  3.不通过filterAppAccess过滤规则的不通过,主要是关于instant app的;
  4.检查包信息内部的授权情况,授权了的话就通过;(核心)
  5.如果检查的权限是ACCESS_COARSE_LOCATION,只要ACCESS_FINE_LOCATION被授权了就通过;如果检查的权限是INTERACT_ACROSS_USERS,只要INTERACT_ACROSS_USERS_FULL被授权了就通过。

 

shouldShowRequestPermissionRationale展示权限申请原因

  这个函数的调用流程是Activity#shouldShowRequestPermissionRationale->PackageManager#shouldShowRequestPermissionRationale-》ApplicationPackageManager#shouldShowRequestPermissionRationale-》。
  先介绍权限的4个flag:FLAG_PERMISSION_SYSTEM_FIXED,FLAG_PERMISSION_POLICY_FIXED,FLAG_PERMISSION_USER_FIXED,FLAG_PERMISSION_USER_SET。
  FLAG_PERMISSION_SYSTEM_FIXED:系统固定,意味着这个权限是系统设定的,应用无法通过grantRuntimePermission/revokeRuntimePermission修改运行时权限的授权状况。这个flag一般由开机授权组件DefaultPermissionGrantPolicy添加,非system的UID不能改动这个flag。
  FLAG_PERMISSION_POLICY_FIXED:设备管理器(DevicePolicyManager)固定,意味着这个权限是DevicePolicyManager设定的,例如全局设置DevicePolicyManager#setPermissionPolicy或者单一应用权限设置 setPermissionGrantState。app除非拥有ADJUST_RUNTIME_PERMISSIONS_POLICY权限,否则无法通过grantRuntimePermission/revokeRuntimePermission修改运行时权限的授权状况,同样,除非拥有ADJUST_RUNTIME_PERMISSIONS_POLICY权限,否则无法改动这个flag。
  FLAG_PERMISSION_USER_FIXED:用户固定,在用户曾经点击过一次拒绝权限的情况下,再点击一次“拒绝,不再询问”的选项后就会为这个权限设置这个flag。这个flag被设置后,运行时权限处于未授权状态,而且不会再弹出相关对话框让用户选择。只有在“应用信息“”的“权限”选项中设置才能重新授权。
  FLAG_PERMISSION_USER_SET:用户设置,在用户首次点击拒绝权限的请款修改被设置。如果上面的FLAG_PERMISSION_XXX_FIXED的flag没有被设置,FLAG_PERMISSION_USER_SET的flag被设置了,shouldShowRequestPermissionRationale就会返回true,这个时候应该向用户展示需要这个权限的原因。

ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE)
public static boolean shouldShowRequestPermissionRationale(@NonNull Activity activity,
            @NonNull String permission) {
        if (Build.VERSION.SDK_INT >= 23) {
            return Api23Impl.shouldShowRequestPermissionRationale(activity, permission);
        }
        return false;
    }
 @DoNotInline
        static boolean shouldShowRequestPermissionRationale(Activity activity, String permission) {
            return activity.shouldShowRequestPermissionRationale(permission);
        }
public boolean shouldShowRequestPermissionRationale(@NonNull String permission) {
        return getPackageManager().shouldShowRequestPermissionRationale(permission);
    }

frameworks\base\core\java\android\content\pm\PackageManager.java

@SuppressWarnings("HiddenAbstractMethod")
    @UnsupportedAppUsage
    public abstract boolean shouldShowRequestPermissionRationale(@NonNull String permName);

frameworks\base\core\java\android\app\ApplicationPackageManager.java

public class ApplicationPackageManager extends PackageManager

@Override @UnsupportedAppUsage
public boolean shouldShowRequestPermissionRationale(String permName) { return getPermissionManager().shouldShowRequestPermissionRationale(permName); }

frameworks\base\core\java\android\permission\PermissionManager.java

  //@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
    public boolean shouldShowRequestPermissionRationale(@NonNull String permissionName) {
        try {
            final String packageName = mContext.getPackageName();
            return mPermissionManager.shouldShowRequestPermissionRationale(packageName,
                    permissionName, mContext.getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

frameworks\base\services\core\java\com\android\server\pm\permission\PermissionManagerService.java

    @Override
    public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
            @UserIdInt int userId) {
        final int callingUid = Binder.getCallingUid();
        if (UserHandle.getCallingUserId() != userId) {
            mContext.enforceCallingPermission(
                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
                    "canShowRequestPermissionRationale for user " + userId);
        }

        final int uid =
                mPackageManagerInt.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, userId);
        if (UserHandle.getAppId(callingUid) != UserHandle.getAppId(uid)) {
            return false;
        }

        if (checkPermission(packageName, permName, userId)
                == PackageManager.PERMISSION_GRANTED) {
            return false;
        }

        final int flags;

        final long identity = Binder.clearCallingIdentity();
        try {
            flags = getPermissionFlagsInternal(packageName, permName, callingUid, userId);
        } finally {
            Binder.restoreCallingIdentity(identity);
        }

        final int fixedFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
                | PackageManager.FLAG_PERMISSION_POLICY_FIXED
                | PackageManager.FLAG_PERMISSION_USER_FIXED;

        if ((flags & fixedFlags) != 0) {
            return false;
        }

        synchronized (mLock) {
            final Permission permission = mRegistry.getPermission(permName);
            if (permission == null) {
                return false;
            }
            if (permission.isHardRestricted()
                    && (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) == 0) {
                return false;
            }
        }

        final long token = Binder.clearCallingIdentity();
        try {
            if (permName.equals(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
                    && mPlatformCompat.isChangeEnabledByPackageName(BACKGROUND_RATIONALE_CHANGE_ID,
                    packageName, userId)) {
                return true;
            }
        } catch (RemoteException e) {
            Log.e(TAG, "Unable to check if compatibility change is enabled.", e);
        } finally {
            Binder.restoreCallingIdentity(token);
        }

        return (flags & PackageManager.FLAG_PERMISSION_USER_SET) != 0;
    }

请求权限requestPermissions

可以看到,requestPermissions主要是构建了一个action是"android.content.pm.action.REQUEST_PERMISSIONS",package是PermissionController的intent,然后唤起相关界面。关于PermissionController apk可以参考谷歌相关说明:
PermissionController

frameworks/base/core/java/android/app/Activity.java

   public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
        if (requestCode < 0) {
            throw new IllegalArgumentException("requestCode should be >= 0");
        }

        if (mHasCurrentPermissionsRequest) {
            Log.w(TAG, "Can request only one set of permissions at a time");
            // Dispatch the callback with empty arrays which means a cancellation.
            onRequestPermissionsResult(requestCode, new String[0], new int[0]);
            return;
        }

        if (!getAttributionSource().getRenouncedPermissions().isEmpty()) {
            final int permissionCount = permissions.length;
            for (int i = 0; i < permissionCount; i++) {
                if (getAttributionSource().getRenouncedPermissions().contains(permissions[i])) {
                    throw new IllegalArgumentException("Cannot request renounced permission: "
                            + permissions[i]);
                }
            }
        }

        final Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions);
        startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null);
        mHasCurrentPermissionsRequest = true;
    }

frameworks\base\core\java\android\content\pm\PackageManager.java

    @NonNull
    @UnsupportedAppUsage
    public Intent buildRequestPermissionsIntent(@NonNull String[] permissions) {
        if (ArrayUtils.isEmpty(permissions)) {
           throw new IllegalArgumentException("permission cannot be null or empty");
        }
        Intent intent = new Intent(ACTION_REQUEST_PERMISSIONS);
        intent.putExtra(EXTRA_REQUEST_PERMISSIONS_NAMES, permissions);
        intent.setPackage(getPermissionControllerPackageName());
        return intent;
    }

packages\modules\Permission\PermissionController响应这个intent的是:packages\modules\Permission\PermissionController\src\com\android\permissioncontroller\permission\ui\GrantPermissionsActivity.java
  这个activity内容比较多,onCreate主要的内容是:
  1.授权回调GrantPermissionsViewHandlerImpl;
  2.权限分组AppPermissionGroup;
  3.展示授权交互界面showNextPermissionGroupGrantRequest;

权限分组AppPermissionGroup

  先从AppPermissionGroup说起。在Permission Controller的apk实现里面,每个运行时权限都属于一个AppPermissionGroup。

packages\modules\Permission\PermissionController\src\com\android\permissioncontroller\permission\model\AppPermissionGroup.java

    public static AppPermissionGroup create(Context context, PackageInfo packageInfo,
            String permissionName, boolean delayChanges) {
        PermissionInfo permissionInfo;
        try {
            permissionInfo = context.getPackageManager().getPermissionInfo(permissionName, 0);
        } catch (PackageManager.NameNotFoundException e) {
            return null;
        }

        if ((permissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
                != PermissionInfo.PROTECTION_DANGEROUS
                || (permissionInfo.flags & PermissionInfo.FLAG_INSTALLED) == 0
                || (permissionInfo.flags & PermissionInfo.FLAG_REMOVED) != 0) {
            return null;
        }

        String group = Utils.getGroupOfPermission(permissionInfo);
        PackageItemInfo groupInfo = permissionInfo;
        if (group != null) {
            try {
                groupInfo = context.getPackageManager().getPermissionGroupInfo(group, 0);
            } catch (PackageManager.NameNotFoundException e) {
                /* ignore */
            }
        }

        List<PermissionInfo> permissionInfos = null;
        if (groupInfo instanceof PermissionGroupInfo) {
            try {
                permissionInfos = Utils.getPermissionInfosForGroup(context.getPackageManager(),
                        groupInfo.name);
            } catch (PackageManager.NameNotFoundException e) {
                /* ignore */
            }
        }

        return create(context, packageInfo, groupInfo, permissionInfos, delayChanges);
    }

PermissionController apk内部划分好的权限组有(下面表格按“|权限|权限组|”的形式呈现),如果在表格里面找不到所属的组,则所属权限组由其android:permissionGroup属性决定。需要注意的是:
  1.如果一个app需要若干运行时权限,那么相同组的权限会被放到一个AppPermissionGroup里面,有些前后台权限的情况除外,例如ACCESS_FINE_LOCATION前台权限和ACCESS_COARSE_LOCATION后台权限都属于android.Manifest.permission_group.LOCATION这个权限组,但是它们是放在两个不同的AppPermissionGroup里面的。
  2.同一个权限,由PermissionController apk内部划分好的权限组和定义权限时android:permissionGroup属性指定的权限组可能不是同一个。执行“adb shell pm list permissions -d -g”命令可以看到定义运行时权限时指定的权限组,其中定义ACCESS_FINE_LOCATION权限时指定的是android.permission-group.UNDEFINED,但是在PermissionController apk被划分到android.Manifest.permission_group.LOCATION。

  3.对于应用需要申请的权限集合mRequestedPermissions,对这个集合里面的所有权限按所在的AppPermissionGroup进行分组,形成一个授权分组GroupState。GroupState内部有一个状态值mState,可以是STATE_UNKNOWN(初始默认值),STATE_ALLOWED(允许授权),STATE_DENIED(拒绝授权),STATE_SKIPPED(跳过授权步骤)。GroupState内部还有一个affectedPermissions集合,包含这个授权分组影响到的所有权限。

前后台权限的AppPermissionGroup

  如果一个权限定义时用android:backgroundPermission指定了另一个权限,那么指定者权限被称为前台权限,被指定者权限被称为后台权限。顾名思义,前台权限指的是应用运行在前台可以获得的权限,后台权限指是应用运行在后台可以获得的权限。
  一个AppPermissionGroup包含的权限如果包含了后台权限,那么会将这些后台权限放到另一个AppPermissionGroup中,并记录在第一个AppPermissionGroup的mBackgroundPermissions中。

 

 

 

(304条消息) Android权限系统(三):运行时权限检查和申请,PermissionController_Invoker123的博客-CSDN博客

(304条消息) Android 权限管理_菜鸟xiaowang的博客-CSDN博客