浅析Android10动态授权流程

2,538 阅读10分钟

做app开发经常需要申请动态权限,比如WRITE_EXTERNAL_STORAGEACCESS_FINE_LOCATION,那么今天就从源码分析,动态权限到底是怎么个流程,Android系统是怎么维护各个app的权限状态的,基于Android 10。对源码敏感的同学可以直接拉到底部看总结

检查权限

首先权限申请入口位于frameworks/base/core/java/android/content/Context.java

public abstract class Context {
    //省略部分代码
	/**
     * Determine whether <em>you</em> have been granted a particular permission.
     *
     * @param permission The name of the permission being checked.
     *
     * @return {@link PackageManager#PERMISSION_GRANTED} if you have the
     * permission, or {@link PackageManager#PERMISSION_DENIED} if not.
     *
     * @see PackageManager#checkPermission(String, String)
     * @see #checkCallingPermission(String)
     */
    @PackageManager.PermissionResult
    public abstract int checkSelfPermission(@NonNull String permission);
    //省略部分代码
}

checkSelfPermission()是一个抽象方法,方法实现在Context的子类frameworks/base/core/java/android/app/ContextImpl.java当中

/**
 * Common implementation of Context API, which provides the base
 * context object for Activity and other application components.
 */
class ContextImpl extends Context {
    //省略部分代码
	@Override
    public int checkSelfPermission(String permission) {
        if (permission == null) {
            throw new IllegalArgumentException("permission is null");
        }

        return checkPermission(permission, Process.myPid(), Process.myUid());
    }
    
    @Override
    public int checkPermission(String permission, int pid, int uid) {
        if (permission == null) {
            throw new IllegalArgumentException("permission is null");
        }
		
        //获取ActivityManagerService代理对象
        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);
            //如果是root用户或者是系统应用,直接返回已授权状态
            if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) {
                Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " holds " + permission);
                return PackageManager.PERMISSION_GRANTED;
            }
            Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " does not hold "
                    + permission);
            return PackageManager.PERMISSION_DENIED;
        }

        try {
            //通过ActivityManagerService来检查权限
            return am.checkPermission(permission, pid, uid);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    //省略部分代码
}

ContextImpl通过frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java来检查权限

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    //省略部分代码
	@Override
    public int checkPermission(String permission, int pid, int uid) {
        if (permission == null) {
            return PackageManager.PERMISSION_DENIED;
        }
        //注意,参数4传的-1,参数5传的true
        return checkComponentPermission(permission, pid, uid, -1, true);
    }
    
    public static int checkComponentPermission(String permission, int pid, int uid,
            int owningUid, boolean exported) {
        //如果是AMS进程调用此方法,则直接返回已授权状态
        if (pid == MY_PID) {
            return PackageManager.PERMISSION_GRANTED;
        }
        return ActivityManager.checkComponentPermission(permission, uid,
                owningUid, exported);
    }
    
    /** @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);
        //如果是root用户或者是系统应用,直接返回已授权状态
        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.
        //owningUid为刚刚我们传的参数4,为-1,所以显然这里不满足
        if (owningUid >= 0 && UserHandle.isSameApp(uid, owningUid)) {
            return PackageManager.PERMISSION_GRANTED;
        }
        // If the target is not exported, then nobody else can get to it.
        //exported为刚刚我们传的参数5,为true,所以显然这里不满足,这里的意思是如果目标进程不对外开放,则任何对象都无法访问
        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 {
            //通过PackageManagerService检查权限
            return AppGlobals.getPackageManager()
                    .checkUidPermission(permission, uid);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    //省略部分代码
}

先是处理了一些特殊情况的逻辑,最终权限判断交由frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java来完成

public class PackageManagerService extends IPackageManager.Stub
        implements PackageSender {
    //省略部分代码
	@Override
    public int checkUidPermission(String permName, int uid) {
        final CheckPermissionDelegate checkPermissionDelegate;
        synchronized (mPackages) {
            if (mCheckPermissionDelegate == null)  {
                return checkUidPermissionImpl(permName, uid);
            }
            checkPermissionDelegate = mCheckPermissionDelegate;
        }
        //最终都执行checkUidPermissionImpl()
        return checkPermissionDelegate.checkUidPermission(permName, uid,
                PackageManagerService.this::checkUidPermissionImpl);
    }
    
    private int checkUidPermissionImpl(String permName, int uid) {
        synchronized (mPackages) {
            //先获取packageName
            final String[] packageNames = getPackagesForUid(uid);
            PackageParser.Package pkg = null;
            final int N = packageNames == null ? 0 : packageNames.length;
            for (int i = 0; pkg == null && i < N; i++) {
                pkg = mPackages.get(packageNames[i]);
            }
            //执行PermissionManagerServiceInternal的checkUidPermission()
            return mPermissionManager.checkUidPermission(permName, pkg, uid, getCallingUid());
        }
    }
    //省略部分代码
}

可以看到,最终会执行PermissionManagerServiceInternalcheckUidPermission()checkUidPermission()是一个抽象方法,由PermissionManagerServiceInternal的子类PermissionManagerService.PermissionManagerServiceInternalImpl来实现

/**
 * Manages all permissions and handles permissions related tasks.
 */
public class PermissionManagerService {
    //省略部分代码
    /**
     * Built-in permissions. Read from system configuration files. Mapping is from
     * UID to permission name.
     */
    private final SparseArray<ArraySet<String>> mSystemPermissions;
    
	private class PermissionManagerServiceInternalImpl extends PermissionManagerServiceInternal {    
        //省略部分代码
		@Override
        public int checkUidPermission(String permName, PackageParser.Package pkg, int uid,
                int callingUid) {
            //执行PermissionManagerService的checkUidPermission()方法
            return PermissionManagerService.this.checkUidPermission(permName, pkg, uid, callingUid);
        }
        //省略部分代码
    }
    
    private int checkUidPermission(String permName, PackageParser.Package pkg, int uid,
            int callingUid) {
        //获取调用此Service的进程uid,也就是调用者的uid
        final int callingUserId = UserHandle.getUserId(callingUid);
        //callingUserId是否为即时应用,我称之为快应用,免安装的那种
        final boolean isCallerInstantApp =
                mPackageManagerInt.getInstantAppPackageName(callingUid) != null;
        //uid是否为即时应用,我称之为快应用,免安装的那种
        final boolean isUidInstantApp =
                mPackageManagerInt.getInstantAppPackageName(uid) != null;
        //获取申请权限的进程id,如果是微信申请权限,则uid指微信,通过日志打印得知,userId与callingUserId相等
        final int userId = UserHandle.getUserId(uid);
        if (!mUserManagerInt.exists(userId)) {
            return PackageManager.PERMISSION_DENIED;
        }

        if (pkg != null) {
            //非常规场景的处理
            if (pkg.mSharedUserId != null) {
                if (isCallerInstantApp) {
                    return PackageManager.PERMISSION_DENIED;
                }
            } else if (mPackageManagerInt.filterAppAccess(pkg, callingUid, callingUserId)) {
                return PackageManager.PERMISSION_DENIED;
            }
            //获取该应用的授权状态,授权状态封装在PermissionState对象当中
            final PermissionsState permissionsState =
                    ((PackageSetting) pkg.mExtras).getPermissionsState();
            //如果已经授权,则返回PERMISSION_GRANTED
            if (permissionsState.hasPermission(permName, userId)) {
                if (isUidInstantApp) {
                    if (mSettings.isPermissionInstant(permName)) {
                        return PackageManager.PERMISSION_GRANTED;
                    }
                } else {
                    return PackageManager.PERMISSION_GRANTED;
                }
            }
            //如果同权限组中有其他的权限已经授权了,则该组其它权限也直接授权,比如ACCESS_FINE_LOCATION授权了,ACCESS_COURSE_LOCATION也会自动授权
            if (isImpliedPermissionGranted(permissionsState, permName, userId)) {
                return PackageManager.PERMISSION_GRANTED;
            }
        } else {
            //如果pkg为空,说明PMS没有扫描到此安装包,此逻辑应用app不用考虑,通过日志,也没有走到此处
            ArraySet<String> perms = mSystemPermissions.get(uid);
            if (perms != null) {
                if (perms.contains(permName)) {
                    return PackageManager.PERMISSION_GRANTED;
                }
                if (FULLER_PERMISSION_MAP.containsKey(permName)
                        && perms.contains(FULLER_PERMISSION_MAP.get(permName))) {
                    return PackageManager.PERMISSION_GRANTED;
                }
            }
        }
        //都不满足则返回PERMISSION_DENIED
        return PackageManager.PERMISSION_DENIED;
    }
    //省略部分代码
}

先从PackageParser.Package中读取mExtral字段,此字段为PackageSetting对象,再通过PackageSetting读取当前应用授权状态PermissionStatePackageParser.Package表示从磁盘读取的APK文件的完整信息(PMS在初始化时会扫描磁盘,这里不做具体分析),我们知道一个APK文件包含很多信息,包名,版本号,所有注册的组件,需要申请的权限等等,具体可参考manifest文件和gradle文件,而我们的权限信息就在mExtral字段当中,而mExtral是一个PackageSetting对象,涉及到安装包配置变更的数据都保存在此对象中,其中我们通过getPermissionsState()拿到授权状态PermissionsState,然后通过hasPermission()判断当前申请的权限是否已经授权

public final class PermissionsState {
    //省略部分代码
    @GuardedBy("mLock")
    private ArrayMap<String, PermissionData> mPermissions;
    
	/**
     * Gets whether the state has a given permission for the specified
     * user, regardless if this is an install or a runtime permission.
     *
     * @param name The permission name.
     * @param userId The device user id.
     * @return Whether the user has the permission.
     */
    public boolean hasPermission(String name, int userId) {
        enforceValidUserId(userId);

        synchronized (mLock) {
            if (mPermissions == null) {
                return false;
            }
            PermissionData permissionData = mPermissions.get(name);

            return permissionData != null && permissionData.isGranted(userId);
        }
    }
    //省略部分代码
}

因为一个ap可能涉及到多个权限申请,所以PermissionsState里定义了一个ArrayMap来保存所有权限的授权状态,map的key为权限名称,value为PermissionDataPermissionData里面定义了一个SparseArray<PermissionsState.PermissionState>,保存所有用户对当前app指定权限的授权情况

    private static final class PermissionData {
        private final BasePermission mPerm;
        private SparseArray<PermissionState> mUserStates = new SparseArray<>();

        public PermissionData(BasePermission perm) {
            mPerm = perm;
        }

        public PermissionData(PermissionData other) {
            this(other.mPerm);
            final int otherStateCount = other.mUserStates.size();
            for (int i = 0; i < otherStateCount; i++) {
                final int otherUserId = other.mUserStates.keyAt(i);
                PermissionState otherState = other.mUserStates.valueAt(i);
                mUserStates.put(otherUserId, new PermissionState(otherState));
            }
        }

        //这里考虑了多用户的情况
        public boolean isGranted(int userId) {
            if (isInstallPermission()) {
                userId = UserHandle.USER_ALL;
            }

            PermissionState userState = mUserStates.get(userId);
            if (userState == null) {
                return false;
            }

            return userState.mGranted;
        }

        //如果用户点击了允许授权,则调用此方法设置
        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.getName());
                mUserStates.put(userId, userState);
            }

            userState.mGranted = true;

            return true;
        }
        //省略部分代码
    }

PermissionsState.PermissionState则是定义了权限的名称和权限的授权情况

public final class PermissionsState {
    //省略部分代码
	public static final class PermissionState {
        //权限名称
        private final String mName;
        //是否授权
        private boolean mGranted;
        private int mFlags;

        public PermissionState(String name) {
            mName = name;
        }

        public PermissionState(PermissionState other) {
            mName = other.mName;
            mGranted = other.mGranted;
            mFlags = other.mFlags;
        }

        public boolean isDefault() {
            return !mGranted && mFlags == 0;
        }

        public String getName() {
            return mName;
        }

        public boolean isGranted() {
            return mGranted;
        }

        public int getFlags() {
            return mFlags;
        }
    }
}

以上是Context.checkPermission()的流程

申请权限

下面再来看看Activity.requestPermissions()的流程,fragment的权限申请也是走的宿主Activity的权限申请流程

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback, WindowControllerCallback,
        AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {
    //省略部分代码
	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;
        }
        //构建Intent
        Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions);
        //启动Activity
        startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null);
        mHasCurrentPermissionsRequest = true;
    }
    //省略部分代码
}

通过PackageManager构建了一个Intent,然后启动了一个Activity

public abstract class PackageManager {
    //省略部分代码
    @SystemApi
    public static final String ACTION_REQUEST_PERMISSIONS =
            "android.content.pm.action.REQUEST_PERMISSIONS";
    
	public Intent buildRequestPermissionsIntent(@NonNull String[] permissions) {
        if (ArrayUtils.isEmpty(permissions)) {
           throw new IllegalArgumentException("permission cannot be null or empty");
        }
        //隐式Intent,注册了ACTION_REQUEST_PERMISSIONS的Activity可以处理此Intent
        Intent intent = new Intent(ACTION_REQUEST_PERMISSIONS);
        intent.putExtra(EXTRA_REQUEST_PERMISSIONS_NAMES, permissions);
        intent.setPackage(getPermissionControllerPackageName());
        return intent;
    }
    //省略部分代码
}

PackageManager启动了一个隐式的Intent,ACTION为android.content.pm.action.REQUEST_PERMISSIONS,那么注册了该ACTION的即可处理此Intent,而GrantPermissionsActivity就注册了此ACTION

        <activity android:name="com.android.packageinstaller.permission.ui.GrantPermissionsActivity"
                android:configChanges="keyboardHidden|screenSize"
                android:excludeFromRecents="true"
                android:theme="@style/GrantPermissions"
                android:visibleToInstantApps="true"
                android:inheritShowWhenLocked="true">
            <intent-filter android:priority="1">
            	<!--注册了目标action-->
                <action android:name="android.content.pm.action.REQUEST_PERMISSIONS" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

可以看到此Activity的theme设置为了GrantPermissions,而此theme的定义为

    <style name="GrantPermissions"
           parent="@android:style/Theme.DeviceDefault.Light.Dialog.Alert">
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowBackground">@android:color/transparent</item>
        <!-- The following attributes change the behavior of the dialog, hence they should not be
             themed -->
        <item name="android:windowIsTranslucent">true</item>
    </style>

风格为对话框,没有窗口标题,透明背景,沉浸式状态栏,不就是我们弹出的授权对话框吗

图1

动态授权.png

再看看Activity的处理

public class GrantPermissionsActivity extends Activity
        implements GrantPermissionsViewHandler.ResultListener {
    //省略部分代码
    private GrantPermissionsViewHandler mViewHandler;
    private String[] mRequestedPermissions;
    
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        //省略部分代码
        
        //获取要申请的权限
        mRequestedPermissions = getIntent().getStringArrayExtra(
                PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES);
        
         // Don't allow legacy apps to request runtime permissions.
        //6.0以下不需要动态授权
        if (callingPackageInfo.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
            // Returning empty arrays means a cancellation.
            mRequestedPermissions = new String[0];
            setResultAndFinish();
            return;
        }
        //省略部分代码
        
        //根据不同的设备创建不同的Handler
        if (DeviceUtils.isTelevision(this)) {
            mViewHandler = new com.android.packageinstaller.permission.ui.television
                    .GrantPermissionsViewHandlerImpl(this,
                    mCallingPackage).setResultListener(this);
        } else if (DeviceUtils.isWear(this)) {
            mViewHandler = new GrantPermissionsWatchViewHandler(this).setResultListener(this);
        } else if (DeviceUtils.isAuto(this)) {
            mViewHandler = new GrantPermissionsAutoViewHandler(this, mCallingPackage, userHandle)
                    .setResultListener(this);
        } else {
            mViewHandler = new com.android.packageinstaller.permission.ui.handheld
                    .GrantPermissionsViewHandlerImpl(this, mCallingPackage, userHandle)
                    .setResultListener(this);
        }
        //省略部分代码
        
        //设置页面布局
        setContentView(mViewHandler.createView());
        //省略部分代码
}

页面布局文件的创建在对应的Handler的createView()方法当中,因为我是在手机上测试的,所以创建的是GrantPermissionsViewHandlerImpl

public class GrantPermissionsViewHandlerImpl implements GrantPermissionsViewHandler,
        OnClickListener {
    //省略部分代码
    
	@Override
    public View createView() {
        mRootView = (ViewGroup) LayoutInflater.from(mActivity)
                .inflate(R.layout.grant_permissions, null);

        int h = mActivity.getResources().getDisplayMetrics().heightPixels;
        mRootView.setMinimumHeight(h);
		//省略部分代码

        return mRootView;
    }
    //省略部分代码
}

打开grant_permissions.xml文件,就是图1中的布局,直接看点击允许和拒绝之后的处理

public class GrantPermissionsViewHandlerImpl implements GrantPermissionsViewHandler,
        OnClickListener {
    //省略部分代码
	@Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.permission_allow_button:
                //点击允许
                if (mResultListener != null) {
                    view.performAccessibilityAction(
                            AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
                    mResultListener.onPermissionGrantResult(mGroupName, GRANTED_ALWAYS);
                }
                break;
            case R.id.permission_allow_always_button:
                //点击始终允许
                if (mResultListener != null) {
                    view.performAccessibilityAction(
                            AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
                    mResultListener.onPermissionGrantResult(mGroupName, GRANTED_ALWAYS);
                }
                break;
            case R.id.permission_allow_foreground_only_button:
                //点击运行期间允许
                if (mResultListener != null) {
                    view.performAccessibilityAction(
                            AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
                    mResultListener.onPermissionGrantResult(mGroupName,
                            GRANTED_FOREGROUND_ONLY);
                }
                break;
            case R.id.permission_deny_button:
                //点击拒绝
                if (mResultListener != null) {
                    view.performAccessibilityAction(
                            AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
                    mResultListener.onPermissionGrantResult(mGroupName, DENIED);
                }
                break;
            case R.id.permission_deny_and_dont_ask_again_button:
                //点击拒绝且不再提示
                if (mResultListener != null) {
                    view.performAccessibilityAction(
                            AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
                    mResultListener.onPermissionGrantResult(mGroupName,
                            DENIED_DO_NOT_ASK_AGAIN);
                }
                break;
			//省略部分代码
        }
    }
    //省略部分代码
}

无论点击什么按钮,都通过ResultListener进行回调,并携带用户选择的结果,GrantPermissionsActivity实现了这个接口,看一下它的处理

public class GrantPermissionsActivity extends Activity
        implements GrantPermissionsViewHandler.ResultListener {
    //省略部分代码
    
	@Override
    public void onPermissionGrantResult(String name,
            @GrantPermissionsViewHandler.Result int result) {
        //记录日志
        logGrantPermissionActivityButtons(name, result);
        GroupState foregroundGroupState = getForegroundGroupState(name);
        GroupState backgroundGroupState = getBackgroundGroupState(name);

        //如果设备处于锁屏状态,先解除锁屏
        if (result == GRANTED_ALWAYS || result == GRANTED_FOREGROUND_ONLY
                || result == DENIED_DO_NOT_ASK_AGAIN) {
            KeyguardManager kgm = getSystemService(KeyguardManager.class);

            if (kgm.isDeviceLocked()) {
                kgm.requestDismissKeyguard(this, new KeyguardManager.KeyguardDismissCallback() {
                            @Override
                            public void onDismissError() {
                                Log.e(LOG_TAG, "Cannot dismiss keyguard perm=" + name + " result="
                                        + result);
                            }

                            @Override
                            public void onDismissCancelled() {
                                // do nothing (i.e. stay at the current permission group)
                            }

                            @Override
                            public void onDismissSucceeded() {
                                // Now the keyguard is dismissed, hence the device is not locked
                                // anymore
                                //解锁后继续执行此方法
                                onPermissionGrantResult(name, result);
                            }
                        });

                return;
            }
        }
		//根据用户选择执行对应的动作
        switch (result) {
            case GRANTED_ALWAYS :
                if (foregroundGroupState != null) {
                    onPermissionGrantResultSingleState(foregroundGroupState, true, false);
                }
                if (backgroundGroupState != null) {
                    onPermissionGrantResultSingleState(backgroundGroupState, true, false);
                }
                break;
            case GRANTED_FOREGROUND_ONLY :
                if (foregroundGroupState != null) {
                    onPermissionGrantResultSingleState(foregroundGroupState, true, false);
                }
                if (backgroundGroupState != null) {
                    onPermissionGrantResultSingleState(backgroundGroupState, false, false);
                }
                break;
            case DENIED :
                if (foregroundGroupState != null) {
                    onPermissionGrantResultSingleState(foregroundGroupState, false, false);
                }
                if (backgroundGroupState != null) {
                    onPermissionGrantResultSingleState(backgroundGroupState, false, false);
                }
                break;
            case DENIED_DO_NOT_ASK_AGAIN :
                if (foregroundGroupState != null) {
                    onPermissionGrantResultSingleState(foregroundGroupState, false, true);
                }
                if (backgroundGroupState != null) {
                    onPermissionGrantResultSingleState(backgroundGroupState, false, true);
                }
                break;
        }

        if (!showNextPermissionGroupGrantRequest()) {
            setResultAndFinish();
        }
    }
    //省略部分代码
}

可以看到最终都会执行onPermissionGrantResultSingleState()

    private void onPermissionGrantResultSingleState(GroupState groupState, boolean granted,
            boolean doNotAskAgain) {
        if (groupState != null && groupState.mGroup != null
                && groupState.mState == GroupState.STATE_UNKNOWN) {
            if (granted) {
                //用户允许授权
                groupState.mGroup.grantRuntimePermissions(doNotAskAgain,
                        groupState.affectedPermissions);
                groupState.mState = GroupState.STATE_ALLOWED;

                reportRequestResult(groupState.affectedPermissions,
                        PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED);
            } else {
                //用户拒绝授权
                groupState.mGroup.revokeRuntimePermissions(doNotAskAgain,
                        groupState.affectedPermissions);
                groupState.mState = GroupState.STATE_DENIED;

                reportRequestResult(groupState.affectedPermissions, doNotAskAgain
                        ?
                        PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE
                        : PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED);
            }
        }
    }

看看允许授权的逻辑

	public boolean grantRuntimePermissions(boolean fixedByTheUser, String[] filterPermissions) {
        boolean killApp = false;
        boolean wasAllGranted = true;
		
        //权限状态配置
        // We toggle permissions only to apps that support runtime
        // permissions, otherwise we toggle the app op corresponding
        // to the permission if the permission is granted to the app.
        for (Permission permission : mPermissions.values()) {
            if (filterPermissions != null
                    && !ArrayUtils.contains(filterPermissions, permission.getName())) {
                continue;
            }

            if (!permission.isGrantingAllowed(mIsEphemeralApp, mAppSupportsRuntimePermissions)) {
                // Skip unallowed permissions.
                continue;
            }

            boolean wasGranted = permission.isGrantedIncludingAppOp();

            if (mAppSupportsRuntimePermissions) {
                // Do not touch permissions fixed by the system.
                if (permission.isSystemFixed()) {
                    wasAllGranted = false;
                    break;
                }

                // Ensure the permission app op enabled before the permission grant.
                if (permission.affectsAppOp() && !permission.isAppOpAllowed()) {
                    permission.setAppOpAllowed(true);
                }

                // Grant the permission if needed.
                if (!permission.isGranted()) {
                    permission.setGranted(true);
                }

                // Update the permission flags.
                if (!fixedByTheUser) {
                    // Now the apps can ask for the permission as the user
                    // no longer has it fixed in a denied state.
                    if (permission.isUserFixed() || permission.isUserSet()) {
                        permission.setUserFixed(false);
                        permission.setUserSet(false);
                    }
                }
            } else {
                // Legacy apps cannot have a not granted permission but just in case.
                if (!permission.isGranted()) {
                    continue;
                }

                // If the permissions has no corresponding app op, then it is a
                // third-party one and we do not offer toggling of such permissions.
                if (permission.affectsAppOp()) {
                    if (!permission.isAppOpAllowed()) {
                        permission.setAppOpAllowed(true);

                        // Legacy apps do not know that they have to retry access to a
                        // resource due to changes in runtime permissions (app ops in this
                        // case). Therefore, we restart them on app op change, so they
                        // can pick up the change.
                        killApp = true;
                    }

                    // Mark that the permission should not be be granted on upgrade
                    // when the app begins supporting runtime permissions.
                    if (permission.shouldRevokeOnUpgrade()) {
                        permission.setRevokeOnUpgrade(false);
                    }
                }

                // Granting a permission explicitly means the user already
                // reviewed it so clear the review flag on every grant.
                if (permission.isReviewRequired()) {
                    permission.unsetReviewRequired();
                }
            }

            // If we newly grant background access to the fine location, double-guess the user some
            // time later if this was really the right choice.
            if (!wasGranted && permission.isGrantedIncludingAppOp()) {
                if (permission.getName().equals(ACCESS_FINE_LOCATION)) {
                    Permission bgPerm = permission.getBackgroundPermission();
                    if (bgPerm != null) {
                        if (bgPerm.isGrantedIncludingAppOp()) {
                            mTriggerLocationAccessCheckOnPersist = true;
                        }
                    }
                } else if (permission.getName().equals(ACCESS_BACKGROUND_LOCATION)) {
                    ArrayList<Permission> fgPerms = permission.getForegroundPermissions();
                    if (fgPerms != null) {
                        int numFgPerms = fgPerms.size();
                        for (int fgPermNum = 0; fgPermNum < numFgPerms; fgPermNum++) {
                            Permission fgPerm = fgPerms.get(fgPermNum);

                            if (fgPerm.getName().equals(ACCESS_FINE_LOCATION)) {
                                if (fgPerm.isGrantedIncludingAppOp()) {
                                    mTriggerLocationAccessCheckOnPersist = true;
                                }

                                break;
                            }
                        }
                    }
                }
            }
        }

        if (!mDelayChanges) {
            //这里很重要,将授权信息持久化保存到本地
            persistChanges(false);

            if (killApp) {
                killApp(KILL_REASON_APP_OP_CHANGE);
            }
        }

        return wasAllGranted;
    }

授权过程就是本地数据配置的过程,最后有一个逻辑很关键,就是将授权信息进行持久化保存,因为当我们关机重启后,需要恢复各个app的授权信息,看看保存到哪儿了

void persistChanges(boolean mayKillBecauseOfAppOpsChange) {
        int uid = mPackageInfo.applicationInfo.uid;

        int numPermissions = mPermissions.size();
        boolean shouldKillApp = false;

        for (int i = 0; i < numPermissions; i++) {
            Permission permission = mPermissions.valueAt(i);

            if (!permission.isSystemFixed()) {
                if (permission.isGranted()) {
                    mPackageManager.grantRuntimePermission(mPackageInfo.packageName,
                            permission.getName(), mUserHandle);
                } else {
                    boolean isCurrentlyGranted = mContext.checkPermission(permission.getName(), -1,
                            uid) == PERMISSION_GRANTED;

                    if (isCurrentlyGranted) {
                        mPackageManager.revokeRuntimePermission(mPackageInfo.packageName,
                                permission.getName(), mUserHandle);
                    }
                }
            }

            int flags = (permission.isUserSet() ? PackageManager.FLAG_PERMISSION_USER_SET : 0)
                    | (permission.isUserFixed() ? PackageManager.FLAG_PERMISSION_USER_FIXED : 0)
                    | (permission.shouldRevokeOnUpgrade()
                    ? PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE : 0)
                    | (permission.isPolicyFixed() ? PackageManager.FLAG_PERMISSION_POLICY_FIXED : 0)
                    | (permission.isReviewRequired()
                    ? PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED : 0);

            //更新权限标识位,这里是去更新PMS里面当前app的权限配置
            mPackageManager.updatePermissionFlags(permission.getName(),
                    mPackageInfo.packageName,
                    PackageManager.FLAG_PERMISSION_USER_SET
                            | PackageManager.FLAG_PERMISSION_USER_FIXED
                            | PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE
                            | PackageManager.FLAG_PERMISSION_POLICY_FIXED
                            | PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED,
                    flags, mUserHandle);

            if (permission.affectsAppOp()) {
                if (!permission.isSystemFixed()) {
                    // Enabling/Disabling an app op may put the app in a situation in which it has
                    // a handle to state it shouldn't have, so we have to kill the app. This matches
                    // the revoke runtime permission behavior.
                    if (permission.isAppOpAllowed()) {
                        shouldKillApp |= allowAppOp(permission, uid);
                    } else {
                        shouldKillApp |= disallowAppOp(permission, uid);
                    }
                }
            }
        }

        if (mayKillBecauseOfAppOpsChange && shouldKillApp) {
            killApp(KILL_REASON_APP_OP_CHANGE);
        }

        if (mTriggerLocationAccessCheckOnPersist) {
            new LocationAccessCheck(mContext, null).checkLocationAccessSoon();
            mTriggerLocationAccessCheckOnPersist = false;
        }
    }

这里通过AIDL,将当前授权信息发送给PMS,使得PMS中保存的当前app的授权信息得以更新

    @Override
    public void updatePermissionFlags(String permissionName, String packageName,
            int flagMask, int flagValues, UserHandle user) {
        try {
        	//跨进程调用,执行PackageManagerService的updatePermissionFlags()
            mPM.updatePermissionFlags(permissionName, packageName, flagMask,
                    flagValues,
                    mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.Q,
                    user.getIdentifier());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

看看PackageManagerService的处理

    @Override
    public void updatePermissionFlags(String permName, String packageName, int flagMask,
            int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) {
        int callingUid = getCallingUid();
        boolean overridePolicy = false;

        if (callingUid != Process.SYSTEM_UID && callingUid != Process.ROOT_UID) {
            long callingIdentity = Binder.clearCallingIdentity();
            try {
                if ((flagMask & FLAG_PERMISSION_POLICY_FIXED) != 0) {
                    if (checkAdjustPolicyFlagPermission) {
                        mContext.enforceCallingOrSelfPermission(
                                Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
                                "Need " + Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY
                                        + " to change policy flags");
                    } else if (!hasTargetSdkInUidLowerThan(callingUid, Build.VERSION_CODES.Q)) {
                        throw new IllegalArgumentException(
                                Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY + " needs "
                                        + " to be checked for packages targeting "
                                        + Build.VERSION_CODES.Q + " or later when changing policy "
                                        + "flags");
                    }

                    overridePolicy = true;
                }
            } finally {
                Binder.restoreCallingIdentity(callingIdentity);
            }
        }
		//通过PermissionManagerService操作
        mPermissionManager.updatePermissionFlags(
                permName, packageName, flagMask, flagValues, callingUid, userId,
                overridePolicy, mPermissionCallback);
    }

最终更新的是PermissionManagerService当中的数据

	private void updatePermissionFlags(String permName, String packageName, int flagMask,
            int flagValues, int callingUid, int userId, boolean overridePolicy,
            PermissionCallback callback) {
        //省略部分代码
        
        //先获取PackageParser.Package
        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
        //省略部分代码
		
        //更新Package的mExtras
        final PackageSetting ps = (PackageSetting) pkg.mExtras;
        final PermissionsState permissionsState = ps.getPermissionsState();
        final boolean hadState =
                permissionsState.getRuntimePermissionState(permName, userId) != null;
        final boolean permissionUpdated =
                permissionsState.updatePermissionFlags(bp, userId, flagMask, flagValues);
        if (permissionUpdated && bp.isRuntime()) {
            notifyRuntimePermissionStateChanged(packageName, userId);
        }
        if (permissionUpdated && callback != null) {
            // Install and runtime permissions are stored in different places,
            // so figure out what permission changed and persist the change.
            if (permissionsState.getInstallPermissionState(permName) != null) {
                //通知安装权限更新,就是不需要动态授权的权限
                callback.onInstallPermissionUpdated();
            } else if (permissionsState.getRuntimePermissionState(permName, userId) != null
                    || hadState) {
                //通知动态权限状态更新
                callback.onPermissionUpdated(new int[] { userId }, false);
            }
        }
    }

可以看到,最终更新的是PackageParser.PackagemExtras字段,上面我们分析知道,在检查权限时,也是读取的PackageParser.PackagemExtras字段,这里就跟前面的逻辑相呼应了,更新完之后,通过callback进行回调,执行持久化存储

        @Override
        public void onPermissionUpdated(int[] updatedUserIds, boolean sync) {
            synchronized (mPackages) {
                for (int userId : updatedUserIds) {
                    mSettings.writeRuntimePermissionsForUserLPr(userId, sync);
                }
            }
        }
    public void writeRuntimePermissionsForUserLPr(int userId, boolean sync) {
        if (sync) {
            mRuntimePermissionsPersistence.writePermissionsForUserSyncLPr(userId);
        } else {
            mRuntimePermissionsPersistence.writePermissionsForUserAsyncLPr(userId);
        }
    }
	private void writePermissionsSync(int userId) {
            //定义持久化保存路径
            AtomicFile destination = new AtomicFile(getUserRuntimePermissionsFile(userId),
                    "package-perms-" + userId);

            //省略部分代码

            FileOutputStream out = null;
            try {
             	//省略部分代码
                //保存到本地
                destination.finishWrite(out);

                if (Build.FINGERPRINT.equals(fingerprint)) {
                    mDefaultPermissionsGranted.put(userId, true);
                }
            // Any error while writing is fatal.
            } catch (Throwable t) {
                Slog.wtf(PackageManagerService.TAG,
                        "Failed to write settings, restoring backup", t);
                destination.failWrite(out);
            } finally {
                IoUtils.closeQuietly(out);
            }
    }

	//文件名
	private static final String RUNTIME_PERMISSIONS_FILE_NAME = "runtime-permissions.xml";

	//获取路径
    private File getUserRuntimePermissionsFile(int userId) {
        // TODO: Implement a cleaner solution when adding tests.
        // This instead of Environment.getUserSystemDirectory(userId) to support testing.
        File userDir = new File(new File(mSystemDir, "users"), Integer.toString(userId));
        File file = new File(userDir, RUNTIME_PERMISSIONS_FILE_NAME);
        Log.d("jasonwan", "getUserRuntimePermissionsFile: file="+file.getAbsolutePath());
        return file;
    }

通过log打印得知,权限文件路径位于/data/system/users/0/runtime-permissions.xml,我们从设备中导出此文件打开看看长啥样

<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<runtime-permissions version="8" fingerprint="qti/trinket/trinket:10/QKQ1.200816.002/2211:userdebug/test-keys">
  <pkg name="com.android.externalstorage">
    <item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="3030" />
    <item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="3030" />
  </pkg>
  <pkg name="com.android.companiondevicemanager">
    <item name="android.permission.ACCESS_FINE_LOCATION" granted="true" flags="30" />
    <item name="android.permission.ACCESS_COARSE_LOCATION" granted="false" flags="b0" />
    <item name="android.permission.ACCESS_BACKGROUND_LOCATION" granted="true" flags="3030" />
  </pkg>
  <pkg name="com.android.quicksearchbox">
    <item name="android.permission.READ_CONTACTS" granted="false" flags="300" />
  </pkg>
  <pkg name="com.android.soundrecorder">
    <item name="android.permission.READ_EXTERNAL_STORAGE" granted="false" flags="2380" />
    <item name="android.permission.READ_PHONE_STATE" granted="false" flags="300" />
    <item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="false" flags="2300" />
    <item name="android.permission.RECORD_AUDIO" granted="true" flags="320" />
    <item name="android.permission.ACCESS_MEDIA_LOCATION" granted="false" flags="380" />
  </pkg>
  <pkg name="com.android.contacts">
    <item name="android.permission.READ_EXTERNAL_STORAGE" granted="false" flags="2300" />
    <item name="android.permission.READ_PHONE_STATE" granted="true" flags="320" />
    <item name="android.permission.CALL_PHONE" granted="true" flags="320" />
    <item name="android.permission.WRITE_CONTACTS" granted="true" flags="320" />
    <item name="android.permission.GET_ACCOUNTS" granted="true" flags="320" />
    <item name="android.permission.READ_CONTACTS" granted="true" flags="320" />
    <item name="android.permission.ACCESS_MEDIA_LOCATION" granted="false" flags="380" />
  </pkg>
  <pkg name="com.android.mms">
    <item name="android.permission.READ_SMS" granted="true" flags="3320" />
    <item name="android.permission.RECEIVE_WAP_PUSH" granted="true" flags="3320" />
    <item name="android.permission.RECEIVE_MMS" granted="true" flags="3320" />
    <item name="android.permission.RECEIVE_SMS" granted="true" flags="3320" />
    <item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="33a0" />
    <item name="android.permission.READ_PHONE_STATE" granted="true" flags="320" />
    <item name="android.permission.SEND_SMS" granted="true" flags="3320" />
    <item name="android.permission.CALL_PHONE" granted="true" flags="320" />
    <item name="android.permission.WRITE_CONTACTS" granted="true" flags="320" />
    <item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="3320" />
    <item name="android.permission.READ_CONTACTS" granted="true" flags="320" />
    <item name="android.permission.ACCESS_MEDIA_LOCATION" granted="true" flags="3a0" />
  </pkg>
  <pkg name="com.android.launcher3">
    <item name="android.permission.READ_EXTERNAL_STORAGE" granted="false" flags="2100" />
    <item name="android.permission.READ_PHONE_STATE" granted="false" flags="100" />
    <item name="android.permission.CALL_PHONE" granted="false" flags="100" />
    <item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="false" flags="2100" />
  </pkg>
  <pkg name="com.android.settings.intelligence">
    <item name="android.permission.READ_PHONE_STATE" granted="false" flags="100" />
  </pkg>
  <pkg name="com.android.calendar">
    <item name="android.permission.READ_CALENDAR" granted="true" flags="320" />
    <item name="android.permission.WRITE_CALENDAR" granted="true" flags="320" />
    <item name="android.permission.GET_ACCOUNTS" granted="true" flags="320" />
    <item name="android.permission.READ_CONTACTS" granted="true" flags="320" />
  </pkg>
  <pkg name="com.android.sharedstoragebackup">
    <item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="30b0" />
    <item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="3030" />
  </pkg>
  <pkg name="com.android.printspooler">
    <item name="android.permission.ACCESS_FINE_LOCATION" granted="true" flags="30" />
    <item name="android.permission.ACCESS_COARSE_LOCATION" granted="true" flags="30" />
  </pkg>
    <!-- 测试Demo-->
  <pkg name="com.jason.nodetest">
    <item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="b00" />
    <item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="b00" />
  </pkg>
  <pkg name="com.android.email">
    <item name="android.permission.READ_CALENDAR" granted="true" flags="320" />
    <item name="android.permission.READ_EXTERNAL_STORAGE" granted="false" flags="2380" />
    <item name="android.permission.READ_PHONE_STATE" granted="false" flags="300" />
    <item name="android.permission.WRITE_CONTACTS" granted="true" flags="320" />
    <item name="android.permission.WRITE_CALENDAR" granted="true" flags="320" />
    <item name="android.permission.GET_ACCOUNTS" granted="true" flags="320" />
    <item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="false" flags="2300" />
    <item name="android.permission.READ_CONTACTS" granted="true" flags="320" />
    <item name="android.permission.ACCESS_MEDIA_LOCATION" granted="false" flags="380" />
  </pkg>
  <pkg name="com.android.music">
    <item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="3320" />
    <item name="android.permission.READ_PHONE_STATE" granted="false" flags="300" />
    <item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="3320" />
    <item name="android.permission.ACCESS_MEDIA_LOCATION" granted="true" flags="3a0" />
  </pkg>
  <shared-user name="android.media">
    <item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="3030" />
    <item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="3030" />
  </shared-user>
  <shared-user name="android.uid.systemui">
    <item name="android.permission.READ_CALL_LOG" granted="true" flags="3030" />
    <item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="3030" />
    <item name="android.permission.ACCESS_COARSE_LOCATION" granted="true" flags="30" />
    <item name="android.permission.CAMERA" granted="true" flags="30" />
    <item name="android.permission.GET_ACCOUNTS" granted="true" flags="30" />
    <item name="android.permission.RECORD_AUDIO" granted="true" flags="30" />
    <item name="android.permission.READ_CONTACTS" granted="true" flags="30" />
  </shared-user>
  <shared-user name="android.uid.nfc">
    <item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="30b0" />
    <item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="3030" />
    <item name="android.permission.READ_CONTACTS" granted="true" flags="30" />
  </shared-user>
  <shared-user name="android.uid.bluetooth">
    <item name="android.permission.READ_SMS" granted="true" flags="3030" />
    <item name="android.permission.READ_CALL_LOG" granted="true" flags="3030" />
    <item name="android.permission.ACCESS_FINE_LOCATION" granted="true" flags="30" />
    <item name="com.android.email.permission.READ_ATTACHMENT" granted="true" flags="1030" />
    <item name="android.permission.RECEIVE_SMS" granted="true" flags="3030" />
    <item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="3030" />
    <item name="android.permission.ACCESS_COARSE_LOCATION" granted="true" flags="30" />
    <item name="android.permission.SEND_SMS" granted="true" flags="3030" />
    <item name="android.permission.WRITE_CONTACTS" granted="true" flags="1030" />
    <item name="android.permission.WRITE_CALL_LOG" granted="true" flags="3030" />
    <item name="android.permission.GET_ACCOUNTS" granted="true" flags="1030" />
    <item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="3030" />
    <item name="android.permission.READ_CONTACTS" granted="true" flags="1030" />
  </shared-user>
  <shared-user name="android.uid.shared">
    <item name="android.permission.READ_PHONE_STATE" granted="true" flags="30" />
    <item name="android.permission.WRITE_CONTACTS" granted="true" flags="30" />
    <item name="android.permission.GET_ACCOUNTS" granted="true" flags="30" />
    <item name="android.permission.READ_CONTACTS" granted="true" flags="30" />
  </shared-user>
  <shared-user name="android.uid.system">
    <item name="android.permission.READ_CALL_LOG" granted="true" flags="3030" />
    <item name="android.permission.ACCESS_FINE_LOCATION" granted="true" flags="1030" />
    <item name="android.permission.RECEIVE_WAP_PUSH" granted="true" flags="3030" />
    <item name="android.permission.RECEIVE_SMS" granted="true" flags="3030" />
    <item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="3030" />
    <item name="android.permission.ACCESS_COARSE_LOCATION" granted="false" flags="10b0" />
    <item name="android.permission.READ_PHONE_STATE" granted="true" flags="1030" />
    <item name="android.permission.SEND_SMS" granted="true" flags="3030" />
    <item name="android.permission.CALL_PHONE" granted="true" flags="1330" />
    <item name="android.permission.WRITE_CONTACTS" granted="true" flags="1330" />
    <item name="android.permission.CAMERA" granted="true" flags="1330" />
    <item name="android.permission.WRITE_CALL_LOG" granted="true" flags="3030" />
    <item name="android.permission.PROCESS_OUTGOING_CALLS" granted="true" flags="3030" />
    <item name="android.permission.GET_ACCOUNTS" granted="true" flags="30" />
    <item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="3030" />
    <item name="android.permission.RECORD_AUDIO" granted="true" flags="1330" />
    <item name="android.permission.READ_CONTACTS" granted="true" flags="1330" />
    <item name="android.permission.ACCESS_BACKGROUND_LOCATION" granted="true" flags="3030" />
    <item name="android.permission.ACCESS_MEDIA_LOCATION" granted="true" flags="1030" />
  </shared-user>
  <shared-user name="android.uid.phone">
    <item name="android.permission.READ_SMS" granted="true" flags="3030" />
    <item name="android.permission.READ_CALL_LOG" granted="true" flags="3030" />
    <item name="android.permission.ACCESS_FINE_LOCATION" granted="true" flags="30" />
    <item name="android.permission.RECEIVE_SMS" granted="true" flags="3030" />
    <item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="3030" />
    <item name="android.permission.ACCESS_COARSE_LOCATION" granted="true" flags="1030" />
    <item name="android.permission.READ_PHONE_STATE" granted="true" flags="30" />
    <item name="android.permission.SEND_SMS" granted="true" flags="3030" />
    <item name="android.permission.CALL_PHONE" granted="true" flags="30" />
    <item name="android.permission.WRITE_CONTACTS" granted="true" flags="30" />
    <item name="android.permission.CAMERA" granted="true" flags="1030" />
    <item name="android.permission.WRITE_CALL_LOG" granted="true" flags="3030" />
    <item name="android.permission.USE_SIP" granted="true" flags="1030" />
    <item name="android.permission.PROCESS_OUTGOING_CALLS" granted="true" flags="3030" />
    <item name="android.permission.GET_ACCOUNTS" granted="true" flags="1030" />
    <item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="3030" />
    <item name="android.permission.RECORD_AUDIO" granted="true" flags="1030" />
    <item name="android.permission.READ_CONTACTS" granted="true" flags="30" />
    <item name="android.permission.ACCESS_BACKGROUND_LOCATION" granted="true" flags="3030" />
    <item name="com.android.voicemail.permission.ADD_VOICEMAIL" granted="true" flags="1030" />
  </shared-user>
  <shared-user name="android.uid.shell">
    <item name="android.permission.READ_SMS" granted="true" flags="3030" />
    <item name="android.permission.READ_CALENDAR" granted="true" flags="30" />
    <item name="android.permission.ACCESS_FINE_LOCATION" granted="true" flags="30" />
    <item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="3030" />
    <item name="android.permission.ACCESS_COARSE_LOCATION" granted="false" flags="30" />
    <item name="android.permission.READ_PHONE_STATE" granted="true" flags="30" />
    <item name="android.permission.SEND_SMS" granted="true" flags="3030" />
    <item name="android.permission.CALL_PHONE" granted="true" flags="30" />
    <item name="android.permission.WRITE_CONTACTS" granted="true" flags="30" />
    <item name="android.permission.WRITE_CALENDAR" granted="true" flags="30" />
    <item name="android.permission.GET_ACCOUNTS" granted="true" flags="30" />
    <item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="3030" />
    <item name="android.permission.READ_CONTACTS" granted="true" flags="30" />
  </shared-user>
  <shared-user name="android.uid.calendar">
    <item name="android.permission.READ_CALENDAR" granted="true" flags="30" />
    <item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="30a0" />
    <item name="android.permission.WRITE_CALENDAR" granted="true" flags="30" />
    <item name="android.permission.GET_ACCOUNTS" granted="true" flags="20" />
    <item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="3020" />
  </shared-user>
  <shared-user name="com.android.emergency.uid">
    <item name="android.permission.READ_CALL_LOG" granted="true" flags="3030" />
    <item name="android.permission.CALL_PHONE" granted="true" flags="30" />
    <item name="android.permission.READ_CONTACTS" granted="true" flags="30" />
  </shared-user>
</runtime-permissions>

可以看到此文件保存就是各个app的动态权限授权情况,安装权限不在此文件中,我们的测试demo包名为com.jason.nodetest,可以看到我们只允许读存储卡权限后,读写权限均为已授权。

同样,当系统重启后,PackageManagerService会初始化并启动,初始化时会从UserServiceManager中获取读取的权限数据

public class PackageManagerService extends IPackageManager.Stub
        implements PackageSender {
    //省略部分代码
	public PackageManagerService(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        	//省略部分代码
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "read user settings");
        	//UserManager创建用户时会去读取用户配置文件,其中就包括runtime-permissions.xml文件
            mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
	        //省略部分代码
    }
    //省略部分代码
}
    boolean readLPw(@NonNull List<UserInfo> users) {
    	//省略部分代码
       	for (UserInfo user : users) {
            //读取所有用户配置信息
            mRuntimePermissionsPersistence.readStateForUserSyncLPr(user.id);
        }
		//省略部分代码
    }
		@GuardedBy("Settings.this.mLock")
        public void readStateForUserSyncLPr(int userId) {
            //获取runtime-permissions.xml文件
            File permissionsFile = getUserRuntimePermissionsFile(userId);
            if (!permissionsFile.exists()) {
                return;
            }

            FileInputStream in;
            try {
                in = new AtomicFile(permissionsFile).openRead();
            } catch (FileNotFoundException fnfe) {
                Slog.i(PackageManagerService.TAG, "No permissions state");
                return;
            }

            try {
                XmlPullParser parser = Xml.newPullParser();
                parser.setInput(in, null);
                //解析runtime-permissions.xml文件
                parseRuntimePermissionsLPr(parser, userId);

            } catch (XmlPullParserException | IOException e) {
                throw new IllegalStateException("Failed parsing permissions file: "
                        + permissionsFile , e);
            } finally {
                IoUtils.closeQuietly(in);
            }
        }

		@GuardedBy("Settings.this.mLock")
        private void parseRuntimePermissionsLPr(XmlPullParser parser, int userId)
                throws IOException, XmlPullParserException {
            final int outerDepth = parser.getDepth();
            int type;
            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                    continue;
                }

                switch (parser.getName()) {
                    case TAG_RUNTIME_PERMISSIONS: {
                        // If the permisions settings file exists but the version is not set this is
                        // an upgrade from P->Q. Hence mark it with the special UPGRADE_VERSION
                        int version = XmlUtils.readIntAttribute(parser, ATTR_VERSION,
                                UPGRADE_VERSION);
                        mVersions.put(userId, version);
                        String fingerprint = parser.getAttributeValue(null, ATTR_FINGERPRINT);
                        mFingerprints.put(userId, fingerprint);
                        final boolean defaultsGranted = Build.FINGERPRINT.equals(fingerprint);
                        mDefaultPermissionsGranted.put(userId, defaultsGranted);
                    } break;

                    case TAG_PACKAGE: {
                        String name = parser.getAttributeValue(null, ATTR_NAME);
                        PackageSetting ps = mPackages.get(name);
                        if (ps == null) {
                            Slog.w(PackageManagerService.TAG, "Unknown package:" + name);
                            XmlUtils.skipCurrentTag(parser);
                            continue;
                        }
                        parsePermissionsLPr(parser, ps.getPermissionsState(), userId);
                    } break;

                    case TAG_SHARED_USER: {
                        //读取shared-user标签,拿到包名
                        String name = parser.getAttributeValue(null, ATTR_NAME);
                        SharedUserSetting sus = mSharedUsers.get(name);
                        if (sus == null) {
                            Slog.w(PackageManagerService.TAG, "Unknown shared user:" + name);
                            XmlUtils.skipCurrentTag(parser);
                            continue;
                        }
                        //解析shared-user下的所有item权限
                        parsePermissionsLPr(parser, sus.getPermissionsState(), userId);
                    } break;
                }
            }
        }

        private void parsePermissionsLPr(XmlPullParser parser, PermissionsState permissionsState,
                int userId) throws IOException, XmlPullParserException {
            final int outerDepth = parser.getDepth();
            int type;
            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                    continue;
                }

                switch (parser.getName()) {
                    case TAG_ITEM: {
                        //读取权限名称
                        String name = parser.getAttributeValue(null, ATTR_NAME);
                        BasePermission bp = mPermissions.getPermission(name);
                        if (bp == null) {
                            Slog.w(PackageManagerService.TAG, "Unknown permission:" + name);
                            XmlUtils.skipCurrentTag(parser);
                            continue;
                        }
						//读取权限授权状态
                        String grantedStr = parser.getAttributeValue(null, ATTR_GRANTED);
                        final boolean granted = grantedStr == null
                                || Boolean.parseBoolean(grantedStr);
						//读取权限的flag
                        String flagsStr = parser.getAttributeValue(null, ATTR_FLAGS);
                        final int flags = (flagsStr != null)
                                ? Integer.parseInt(flagsStr, 16) : 0;
						//给权限赋值
                        if (granted) {
                            permissionsState.grantRuntimePermission(bp, userId);
                            permissionsState.updatePermissionFlags(bp, userId,
                                        PackageManager.MASK_PERMISSION_FLAGS_ALL, flags);
                        } else {
                            permissionsState.updatePermissionFlags(bp, userId,
                                    PackageManager.MASK_PERMISSION_FLAGS_ALL, flags);
                        }

                    } break;
                }
            }

可以看到,从runtime-permissions.xml文件中读取的授权信息最终赋值给了PermissionsState,而我们在检查权限时也是从PermissionState中获取的权限授权状态,这里跟前面形成了闭环。

总结

以上就是Android 10动态授权的整个流程,简单总结下就是

1、Android启动,PackageManagerService启动,扫描APK获取所有权限

2、读取runtime-permissions.xml文件,获取动态权限授权情况,并将他赋值给PermissionState

3、用户检查权限,从PermissionState中获取目标权限的授权状态,并返给app

4、用户申请权限,根据用户的选择,设置PermissionState中对应权限的状态,并持久化存储到runtime-permissions.xml文件中