一.SystemConfig的整机权限信息

  Android在SystemConfig的构造函数中会通过读取相关的文件来加载整机的权限信息。这些文件是{partition}/etc/permissions下面的文件。其中{partition}指代的分区包含了/system,/vendor,/odm,/oem/,/product/,/system_ext等目录。{partition}/etc/permissions目录下的文件以xml的形式存在以方便解析。

frameworks/base/core/java/com/android/server/SystemConfig.java

    SystemConfig() {        // Read configuration from system        readPermissions(Environment.buildPath(                Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);        // Read configuration from the old permissions dir        readPermissions(Environment.buildPath(                Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);        // Vendors are only allowed to customize these        int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS                | ALLOW_ASSOCIATIONS;        if (Build.VERSION.FIRST_SDK_INT <= Build.VERSION_CODES.O_MR1) {            // For backward compatibility            vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS);        }        readPermissions(Environment.buildPath(                Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag);        readPermissions(Environment.buildPath(                Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);        // Allow ODM to customize system configs as much as Vendor, because /odm is another        // vendor partition other than /vendor.        int odmPermissionFlag = vendorPermissionFlag;        readPermissions(Environment.buildPath(                Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);        readPermissions(Environment.buildPath(                Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);        String skuProperty = SystemProperties.get(SKU_PROPERTY, "");        if (!skuProperty.isEmpty()) {            String skuDir = "sku_" + skuProperty;            readPermissions(Environment.buildPath(                    Environment.getOdmDirectory(), "etc", "sysconfig", skuDir), odmPermissionFlag);            readPermissions(Environment.buildPath(                    Environment.getOdmDirectory(), "etc", "permissions", skuDir),                    odmPermissionFlag);        }        // Allow OEM to customize these        int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS | ALLOW_ASSOCIATIONS;        readPermissions(Environment.buildPath(                Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag);        readPermissions(Environment.buildPath(                Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag);        // Allow Product to customize all system configs        readPermissions(Environment.buildPath(                Environment.getProductDirectory(), "etc", "sysconfig"), ALLOW_ALL);        readPermissions(Environment.buildPath(                Environment.getProductDirectory(), "etc", "permissions"), ALLOW_ALL);        // Allow /system_ext to customize all system configs        readPermissions(Environment.buildPath(                Environment.getSystemExtDirectory(), "etc", "sysconfig"), ALLOW_ALL);        readPermissions(Environment.buildPath(                Environment.getSystemExtDirectory(), "etc", "permissions"), ALLOW_ALL);        // Skip loading configuration from apex if it is not a system process.        if (!isSystemProcess()) {            return;        }        // Read configuration of libs from apex module.        // TODO(146407631): Use a solid way to filter apex module folders?        for (File f: FileUtils.listFilesOrEmpty(Environment.getApexDirectory())) {            if (f.isFile() || f.getPath().contains("@")) {                continue;            }            readPermissions(Environment.buildPath(f, "etc", "permissions"), ALLOW_LIBS);        }    }

  解析的规则如下。选取一些常用的进行说明:
1.permission标签:定义了一个权限,name为权限的名称,子标签gid表示权限所属的gid,一个权限可以同时属于几个不同的gid;
2.assign-permission标签:授予某个uid某个特定权限;
3.split-permission标签:当系统授予某个应用某个split permission时,如果应用的targetsdk低于split-permission的targetsdk(没有指定的话targetsdk为10001)会同时授予new-permission子标签对应的权限;
4.feature标签:定义系统的特性(feature);
5.unavailable-feature标签:定义了需要移除的系统特性(feature);
6.system-user-whitelisted-app标签:主用户下强制启用的system app;
7.system-user-blacklisted-app标签:主用户下强制不启用的system app;
8.library标签:定义了应用的共享jar包;
9.privapp-permissions标签:为特权应用授予或拒绝权限。如果特权应用需要使用到级别signature|privileged的系统权限,必须显式地在在permission子标签下声明授予权限或者在deny-permission字标签下声明不授予权限,两者必选其一,不然会造成开不了机。参考特许权限白名单;

frameworks/base/core/java/com/android/server/SystemConfig.java

    private void readPermissionsFromXml(File permFile, int permissionFlag) {        FileReader permReader = null;        try {            permReader = new FileReader(permFile);        } catch (FileNotFoundException e) {            Slog.w(TAG, "Couldn't find or open permissions file " + permFile);            return;        }        final boolean lowRam = ActivityManager.isLowRamDeviceStatic();        try {            XmlPullParser parser = Xml.newPullParser();            parser.setInput(permReader);            int type;            while ((type=parser.next()) != parser.START_TAG                       && type != parser.END_DOCUMENT) {                ;            }            if (type != parser.START_TAG) {                throw new XmlPullParserException("No start tag found");            }            if (!parser.getName().equals("permissions") && !parser.getName().equals("config")) {                throw new XmlPullParserException("Unexpected start tag in " + permFile                        + ": found " + parser.getName() + ", expected 'permissions' or 'config'");            }            final boolean allowAll = permissionFlag == ALLOW_ALL;            final boolean allowLibs = (permissionFlag & ALLOW_LIBS) != 0;            final boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0;            final boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0;            final boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0;            final boolean allowPrivappPermissions = (permissionFlag & ALLOW_PRIVAPP_PERMISSIONS)                    != 0;            final boolean allowOemPermissions = (permissionFlag & ALLOW_OEM_PERMISSIONS) != 0;            final boolean allowApiWhitelisting = (permissionFlag & ALLOW_HIDDENAPI_WHITELISTING)                    != 0;            final boolean allowAssociations = (permissionFlag & ALLOW_ASSOCIATIONS) != 0;            while (true) {                XmlUtils.nextElement(parser);                if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {                    break;                }                String name = parser.getName();                if (name == null) {                    XmlUtils.skipCurrentTag(parser);                    continue;                }                switch (name) {                    case "group": {                        if (allowAll) {                            String gidStr = parser.getAttributeValue(null, "gid");                            if (gidStr != null) {                                int gid = android.os.Process.getGidForName(gidStr);                                mGlobalGids = appendInt(mGlobalGids, gid);                            } else {                                Slog.w(TAG, "<" + name + "> without gid in " + permFile + " at "                                        + parser.getPositionDescription());                            }                        } else {                            logNotAllowedInPartition(name, permFile, parser);                        }                        XmlUtils.skipCurrentTag(parser);                    } break;                    case "permission": {                        if (allowPermissions) {                            String perm = parser.getAttributeValue(null, "name");                            if (perm == null) {                                Slog.w(TAG, "<" + name + "> without name in " + permFile + " at "                                        + parser.getPositionDescription());                                XmlUtils.skipCurrentTag(parser);                                break;                            }                            perm = perm.intern();                            readPermission(parser, perm);                        } else {                            logNotAllowedInPartition(name, permFile, parser);                            XmlUtils.skipCurrentTag(parser);                        }                    } break;                    case "assign-permission": {                        if (allowPermissions) {                            String perm = parser.getAttributeValue(null, "name");                            if (perm == null) {                                Slog.w(TAG, "<" + name + "> without name in " + permFile                                        + " at " + parser.getPositionDescription());                                XmlUtils.skipCurrentTag(parser);                                break;                            }                            String uidStr = parser.getAttributeValue(null, "uid");                            if (uidStr == null) {                                Slog.w(TAG, "<" + name + "> without uid in " + permFile                                        + " at " + parser.getPositionDescription());                                XmlUtils.skipCurrentTag(parser);                                break;                            }                            int uid = Process.getUidForName(uidStr);                            if (uid < 0) {                                Slog.w(TAG, "<" + name + "> with unknown uid \""                                        + uidStr + "  in " + permFile + " at "                                        + parser.getPositionDescription());                                XmlUtils.skipCurrentTag(parser);                                break;                            }                            perm = perm.intern();                            ArraySet perms = mSystemPermissions.get(uid);                            if (perms == null) {                                perms = new ArraySet();                                mSystemPermissions.put(uid, perms);                            }                            perms.add(perm);                        } else {                            logNotAllowedInPartition(name, permFile, parser);                        }                        XmlUtils.skipCurrentTag(parser);                    } break;                    case "split-permission": {                        if (allowPermissions) {                            readSplitPermission(parser, permFile);                        } else {                            logNotAllowedInPartition(name, permFile, parser);                            XmlUtils.skipCurrentTag(parser);                        }                    } break;                    case "library": {                        if (allowLibs) {                            String lname = parser.getAttributeValue(null, "name");                            String lfile = parser.getAttributeValue(null, "file");                            String ldependency = parser.getAttributeValue(null, "dependency");                            if (lname == null) {                                Slog.w(TAG, "<" + name + "> without name in " + permFile + " at "                                        + parser.getPositionDescription());                            } else if (lfile == null) {                                Slog.w(TAG, "<" + name + "> without file in " + permFile + " at "                                        + parser.getPositionDescription());                            } else {                                //Log.i(TAG, "Got library " + lname + " in " + lfile);                                SharedLibraryEntry entry = new SharedLibraryEntry(lname, lfile,                                        ldependency == null ? new String[0] : ldependency.split(":"));                                mSharedLibraries.put(lname, entry);                            }                        } else {                            logNotAllowedInPartition(name, permFile, parser);                        }                        XmlUtils.skipCurrentTag(parser);                    } break;                    case "feature": {                        if (allowFeatures) {                            String fname = parser.getAttributeValue(null, "name");                            int fversion = XmlUtils.readIntAttribute(parser, "version", 0);                            boolean allowed;                            if (!lowRam) {                                allowed = true;                            } else {                                String notLowRam = parser.getAttributeValue(null, "notLowRam");                                allowed = !"true".equals(notLowRam);                            }                            if (fname == null) {                                Slog.w(TAG, "<" + name + "> without name in " + permFile + " at "                                        + parser.getPositionDescription());                            } else if (allowed) {                                addFeature(fname, fversion);                            }                        } else {                            logNotAllowedInPartition(name, permFile, parser);                        }                        XmlUtils.skipCurrentTag(parser);                    } break;                    case "unavailable-feature": {                        if (allowFeatures) {                            String fname = parser.getAttributeValue(null, "name");                            if (fname == null) {                                Slog.w(TAG, "<" + name + "> without name in " + permFile                                        + " at " + parser.getPositionDescription());                            } else {                                mUnavailableFeatures.add(fname);                            }                        } else {                            logNotAllowedInPartition(name, permFile, parser);                        }                        XmlUtils.skipCurrentTag(parser);                    } break;                    case "allow-in-power-save-except-idle": {                        if (allowAll) {                            String pkgname = parser.getAttributeValue(null, "package");                            if (pkgname == null) {                                Slog.w(TAG, "<" + name + "> without package in "                                        + permFile + " at " + parser.getPositionDescription());                            } else {                                mAllowInPowerSaveExceptIdle.add(pkgname);                            }                        } else {                            logNotAllowedInPartition(name, permFile, parser);                        }                        XmlUtils.skipCurrentTag(parser);                    } break;                    case "allow-in-power-save": {                        if (allowAll) {                            String pkgname = parser.getAttributeValue(null, "package");                            if (pkgname == null) {                                Slog.w(TAG, "<" + name + "> without package in "                                        + permFile + " at " + parser.getPositionDescription());                            } else {                                mAllowInPowerSave.add(pkgname);                            }                        } else {                            logNotAllowedInPartition(name, permFile, parser);                        }                        XmlUtils.skipCurrentTag(parser);                    } break;                    case "allow-in-data-usage-save": {                        if (allowAll) {                            String pkgname = parser.getAttributeValue(null, "package");                            if (pkgname == null) {                                Slog.w(TAG, "<" + name + "> without package in "                                        + permFile + " at " + parser.getPositionDescription());                            } else {                                mAllowInDataUsageSave.add(pkgname);                            }                        } else {                            logNotAllowedInPartition(name, permFile, parser);                        }                        XmlUtils.skipCurrentTag(parser);                    } break;                    case "allow-unthrottled-location": {                        if (allowAll) {                            String pkgname = parser.getAttributeValue(null, "package");                            if (pkgname == null) {                                Slog.w(TAG, "<" + name + "> without package in "                                        + permFile + " at " + parser.getPositionDescription());                            } else {                                mAllowUnthrottledLocation.add(pkgname);                            }                        } else {                            logNotAllowedInPartition(name, permFile, parser);                        }                        XmlUtils.skipCurrentTag(parser);                    } break;                    case "allow-ignore-location-settings": {                        if (allowAll) {                            String pkgname = parser.getAttributeValue(null, "package");                            if (pkgname == null) {                                Slog.w(TAG, "<" + name + "> without package in "                                        + permFile + " at " + parser.getPositionDescription());                            } else {                                mAllowIgnoreLocationSettings.add(pkgname);                            }                        } else {                            logNotAllowedInPartition(name, permFile, parser);                        }                        XmlUtils.skipCurrentTag(parser);                    } break;                    case "allow-implicit-broadcast": {                        if (allowAll) {                            String action = parser.getAttributeValue(null, "action");                            if (action == null) {                                Slog.w(TAG, "<" + name + "> without action in "                                        + permFile + " at " + parser.getPositionDescription());                            } else {                                mAllowImplicitBroadcasts.add(action);                            }                        } else {                            logNotAllowedInPartition(name, permFile, parser);                        }                        XmlUtils.skipCurrentTag(parser);                    } break;                    case "app-link": {                        if (allowAppConfigs) {                            String pkgname = parser.getAttributeValue(null, "package");                            if (pkgname == null) {                                Slog.w(TAG, "<" + name + "> without package in " + permFile                                        + " at " + parser.getPositionDescription());                            } else {                                mLinkedApps.add(pkgname);                            }                        } else {                            logNotAllowedInPartition(name, permFile, parser);                        }                        XmlUtils.skipCurrentTag(parser);                    } break;                    case "system-user-whitelisted-app": {                        if (allowAppConfigs) {                            String pkgname = parser.getAttributeValue(null, "package");                            if (pkgname == null) {                                Slog.w(TAG, "<" + name + "> without package in "                                        + permFile + " at " + parser.getPositionDescription());                            } else {                                mSystemUserWhitelistedApps.add(pkgname);                            }                        } else {                            logNotAllowedInPartition(name, permFile, parser);                        }                        XmlUtils.skipCurrentTag(parser);                    } break;                    case "system-user-blacklisted-app": {                        if (allowAppConfigs) {                            String pkgname = parser.getAttributeValue(null, "package");                            if (pkgname == null) {                                Slog.w(TAG, "<" + name + "> without package in "                                        + permFile + " at " + parser.getPositionDescription());                            } else {                                mSystemUserBlacklistedApps.add(pkgname);                            }                        } else {                            logNotAllowedInPartition(name, permFile, parser);                        }                        XmlUtils.skipCurrentTag(parser);                    } break;                    case "default-enabled-vr-app": {                        if (allowAppConfigs) {                            String pkgname = parser.getAttributeValue(null, "package");                            String clsname = parser.getAttributeValue(null, "class");                            if (pkgname == null) {                                Slog.w(TAG, "<" + name + "> without package in "                                        + permFile + " at " + parser.getPositionDescription());                            } else if (clsname == null) {                                Slog.w(TAG, "<" + name + "> without class in "                                        + permFile + " at " + parser.getPositionDescription());                            } else {                                mDefaultVrComponents.add(new ComponentName(pkgname, clsname));                            }                        } else {                            logNotAllowedInPartition(name, permFile, parser);                        }                        XmlUtils.skipCurrentTag(parser);                    } break;                    case "backup-transport-whitelisted-service": {                        if (allowFeatures) {                            String serviceName = parser.getAttributeValue(null, "service");                            if (serviceName == null) {                                Slog.w(TAG, "<" + name + "> without service in "                                        + permFile + " at " + parser.getPositionDescription());                            } else {                                ComponentName cn = ComponentName.unflattenFromString(serviceName);                                if (cn == null) {                                    Slog.w(TAG, "<" + name + "> with invalid service name "                                            + serviceName + " in " + permFile                                            + " at " + parser.getPositionDescription());                                } else {                                    mBackupTransportWhitelist.add(cn);                                }                            }                        } else {                            logNotAllowedInPartition(name, permFile, parser);                        }                        XmlUtils.skipCurrentTag(parser);                    } break;                    case "disabled-until-used-preinstalled-carrier-associated-app": {                        if (allowAppConfigs) {                            String pkgname = parser.getAttributeValue(null, "package");                            String carrierPkgname = parser.getAttributeValue(null,                                    "carrierAppPackage");                            if (pkgname == null || carrierPkgname == null) {                                Slog.w(TAG, "<" + name                                        + "> without package or carrierAppPackage in " + permFile                                        + " at " + parser.getPositionDescription());                            } else {                                List associatedPkgs =                                        mDisabledUntilUsedPreinstalledCarrierAssociatedApps.get(                                                carrierPkgname);                                if (associatedPkgs == null) {                                    associatedPkgs = new ArrayList<>();                                    mDisabledUntilUsedPreinstalledCarrierAssociatedApps.put(                                            carrierPkgname, associatedPkgs);                                }                                associatedPkgs.add(pkgname);                            }                        } else {                            logNotAllowedInPartition(name, permFile, parser);                        }                        XmlUtils.skipCurrentTag(parser);                    } break;                    case "disabled-until-used-preinstalled-carrier-app": {                        if (allowAppConfigs) {                            String pkgname = parser.getAttributeValue(null, "package");                            if (pkgname == null) {                                Slog.w(TAG,                                        "<" + name + "> without "                                                + "package in " + permFile + " at "                                                + parser.getPositionDescription());                            } else {                                mDisabledUntilUsedPreinstalledCarrierApps.add(pkgname);                            }                        } else {                            logNotAllowedInPartition(name, permFile, parser);                        }                        XmlUtils.skipCurrentTag(parser);                    } break;                    case "privapp-permissions": {                        if (allowPrivappPermissions) {                            // privapp permissions from system, vendor, product and system_ext                            // partitions are stored separately. This is to prevent xml files in                            // the vendor partition from granting permissions to priv apps in the                            // system partition and vice versa.                            boolean vendor = permFile.toPath().startsWith(                                    Environment.getVendorDirectory().toPath() + "/")                                    || permFile.toPath().startsWith(                                    Environment.getOdmDirectory().toPath() + "/");                            boolean product = permFile.toPath().startsWith(                                    Environment.getProductDirectory().toPath() + "/");                            boolean systemExt = permFile.toPath().startsWith(                                    Environment.getSystemExtDirectory().toPath() + "/");                            if (vendor) {                                readPrivAppPermissions(parser, mVendorPrivAppPermissions,                                        mVendorPrivAppDenyPermissions);                            } else if (product) {                                readPrivAppPermissions(parser, mProductPrivAppPermissions,                                        mProductPrivAppDenyPermissions);                            } else if (systemExt) {                                readPrivAppPermissions(parser, mSystemExtPrivAppPermissions,                                        mSystemExtPrivAppDenyPermissions);                            } else {                                readPrivAppPermissions(parser, mPrivAppPermissions,                                        mPrivAppDenyPermissions);                            }                        } else {                            logNotAllowedInPartition(name, permFile, parser);                            XmlUtils.skipCurrentTag(parser);                        }                    } break;                    case "oem-permissions": {                        if (allowOemPermissions) {                            readOemPermissions(parser);                        } else {                            logNotAllowedInPartition(name, permFile, parser);                            XmlUtils.skipCurrentTag(parser);                        }                    } break;                    case "hidden-api-whitelisted-app": {                        if (allowApiWhitelisting) {                            String pkgname = parser.getAttributeValue(null, "package");                            if (pkgname == null) {                                Slog.w(TAG, "<" + name + "> without package in "                                        + permFile + " at " + parser.getPositionDescription());                            } else {                                mHiddenApiPackageWhitelist.add(pkgname);                            }                        } else {                            logNotAllowedInPartition(name, permFile, parser);                        }                        XmlUtils.skipCurrentTag(parser);                    } break;                    case "allow-association": {                        if (allowAssociations) {                            String target = parser.getAttributeValue(null, "target");                            if (target == null) {                                Slog.w(TAG, "<" + name + "> without target in " + permFile                                        + " at " + parser.getPositionDescription());                                XmlUtils.skipCurrentTag(parser);                                break;                            }                            String allowed = parser.getAttributeValue(null, "allowed");                            if (allowed == null) {                                Slog.w(TAG, "<" + name + "> without allowed in " + permFile                                        + " at " + parser.getPositionDescription());                                XmlUtils.skipCurrentTag(parser);                                break;                            }                            target = target.intern();                            allowed = allowed.intern();                            ArraySet associations = mAllowedAssociations.get(target);                            if (associations == null) {                                associations = new ArraySet<>();                                mAllowedAssociations.put(target, associations);                            }                            Slog.i(TAG, "Adding association: " + target + " <- " + allowed);                            associations.add(allowed);                        } else {                            logNotAllowedInPartition(name, permFile, parser);                        }                        XmlUtils.skipCurrentTag(parser);                    } break;                    case "bugreport-whitelisted": {                        String pkgname = parser.getAttributeValue(null, "package");                        if (pkgname == null) {                            Slog.w(TAG, "<" + name + "> without package in " + permFile                                    + " at " + parser.getPositionDescription());                        } else {                            mBugreportWhitelistedPackages.add(pkgname);                        }                        XmlUtils.skipCurrentTag(parser);                    } break;                    default: {                        Slog.w(TAG, "Tag " + name + " is unknown in "                                + permFile + " at " + parser.getPositionDescription());                        XmlUtils.skipCurrentTag(parser);                    } break;                }            }        } catch (XmlPullParserException e) {            Slog.w(TAG, "Got exception parsing permissions.", e);        } catch (IOException e) {            Slog.w(TAG, "Got exception parsing permissions.", e);        } finally {            IoUtils.closeQuietly(permReader);        }        // Some devices can be field-converted to FBE, so offer to splice in        // those features if not already defined by the static config        if (StorageManager.isFileEncryptedNativeOnly()) {            addFeature(PackageManager.FEATURE_FILE_BASED_ENCRYPTION, 0);            addFeature(PackageManager.FEATURE_SECURELY_REMOVES_USERS, 0);        }        // Help legacy devices that may not have updated their static config        if (StorageManager.hasAdoptable()) {            addFeature(PackageManager.FEATURE_ADOPTABLE_STORAGE, 0);        }        if (ActivityManager.isLowRamDeviceStatic()) {            addFeature(PackageManager.FEATURE_RAM_LOW, 0);        } else {            addFeature(PackageManager.FEATURE_RAM_NORMAL, 0);        }        for (String featureName : mUnavailableFeatures) {            removeFeature(featureName);        }    }

Settings#readLPw和Settings#writeLPr

  在开机阶段,PMS扫描应用之前,PMS会调用Settings#readLPw来初始化权限信息。如果是首次开机,这个步骤会被跳过;如果不是首次开机,Settings#readLPw将会读取系统的/data/system/packages.xml和data/system/users/{userid}/runtime-permissions.xml来获取上次关机时刻保存的安装权限信息和运行时权限信息。

frameworks/base/services/core/ava/com/android/server/pm/PackageManagerService.java

    public PackageManagerService(Context context, Installer installer,        boolean factoryTest, boolean onlyCore) {        ...                    mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));                    ...

  packages.xml和权限相关的节点主要有permissions节点,permission-trees节点还有package节点下的perms子节点。
  permissions节点形式如下所示。每一个item代表了一个定义的权限。name是权限的名称,package是定义这个权限的包名,protection是这个权限的安全级别。

                                    ...            

  permission-trees节点形式如下所示。每一个item代表了一个定义的权限树。name是权限树的名称,package是定义这个权限树的包名。
  读取permissions节点的结果是更新Settings–>mPermissions(PermissionSettings)–>mPermissions(ArrayMap)数据结构。读取permission-trees节点的结果是更新Settings–>mPermissions(PermissionSettings)–>mPermissionTrees(ArrayMap)数据结构。

                

  package节点下的perms子节点如下。每一个Item表示和应用相关的安装权限(就是除了运行时权限以外的权限,运行时权限信息在 /data/system/users/{userid}/runtime-permissions.xml体现)信息。granted表示授权状态。flags表示这个权限的flag。

                                                                                                                

  读取package节点的结果是更新Settings–>mPackages(ArrayMap),插入应用包名为键,记录包信息的PackageSetting为值的记录。

frameworks/base/services/core/java/com/android/server/pm/Settings.java

    private void readPackageLPw(XmlPullParser parser) throws XmlPullParserException, IOException {           ...            } else if (userId > 0) {//独立UID应用,构建一个PackageSetting后记录到Settings-->mPackages                packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),                        new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString,                        secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags,                        pkgPrivateFlags, parentPackageName, null /*childPackageNames*/,                        null /*usesStaticLibraries*/, null /*usesStaticLibraryVersions*/);           ...            } else if (sharedIdStr != null) {                if (sharedUserId > 0) {//shareduserid应用,构建一个PackageSetting在解析packages.xml完成后记录到Settings-->mPackages,因为可能存在多个应用共用shareduserid,所以必须在解析packages.xml完成后才记录到Settings-->mPackages,方便在对应的SharedUserSetting记录所有共用这个shareduserid的应用                    packageSetting = new PackageSetting(name.intern(), realName, new File(                            codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr,                            primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,                            versionCode, pkgFlags, pkgPrivateFlags, parentPackageName,                            null /*childPackageNames*/, sharedUserId,                            null /*usesStaticLibraries*/, null /*usesStaticLibraryVersions*/);                    packageSetting.setTimeStamp(timeStamp);                    packageSetting.firstInstallTime = firstInstallTime;                    packageSetting.lastUpdateTime = lastUpdateTime;                    mPendingPackages.add(packageSetting);                    if (PackageManagerService.DEBUG_SETTINGS)                        Log.i(PackageManagerService.TAG, "Reading package " + name                                + ": sharedUserId=" + sharedUserId + " pkg=" + packageSetting);              ...                } else if (tagName.equals(TAG_PERMISSIONS)) {//解析package的权限信息                    readInstallPermissionsLPr(parser,                            packageSetting.getPermissionsState());                    packageSetting.installPermissionsFixed = true;               ...    }

  前面提过packages.xml中package标签下的perms标签的每一项权限都是安装权限,根据其granted的值来预先设置权限状态。granted为true,使用grantInstallPermission授予安装权限并设置flags标签表示的flag;granted为false,使用revokeInstallPermission移除安装权限设置flags标签表示的flag。

frameworks/base/services/core/java/com/android/server/pm/Settings.java

    void readInstallPermissionsLPr(XmlPullParser parser,            PermissionsState permissionsState) throws IOException, XmlPullParserException {        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;            }            String tagName = parser.getName();            if (tagName.equals(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);                String flagsStr = parser.getAttributeValue(null, ATTR_FLAGS);                final int flags = (flagsStr != null)                        ? Integer.parseInt(flagsStr, 16) : 0;                if (granted) {                    if (permissionsState.grantInstallPermission(bp) ==                            PermissionsState.PERMISSION_OPERATION_FAILURE) {                        Slog.w(PackageManagerService.TAG, "Permission already added: " + name);                        XmlUtils.skipCurrentTag(parser);                    } else {                        permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,                                PackageManager.MASK_PERMISSION_FLAGS_ALL, flags);                    }                } else {                    if (permissionsState.revokeInstallPermission(bp) ==                            PermissionsState.PERMISSION_OPERATION_FAILURE) {                        Slog.w(PackageManagerService.TAG, "Permission already added: " + name);                        XmlUtils.skipCurrentTag(parser);                    } else {                        permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,                                PackageManager.MASK_PERMISSION_FLAGS_ALL, flags);                    }                }            } else {                Slog.w(PackageManagerService.TAG, "Unknown element under : "                        + parser.getName());                XmlUtils.skipCurrentTag(parser);            }        }    }

  读取运行时权限信息代码入口:

frameworks/base/services/core/java/com/android/server/pm/Settings.java

    boolean readLPw(@NonNull List users) {    ...        for (UserInfo user : users) {            mRuntimePermissionsPersistence.readStateForUserSyncLPr(user.id);        }        ...

  data/system/users/{userid}/runtime-permissions.xml部分内容如下。安装权限是对用所有用户都生效的,运行时权限时在不同用户下可能有不同的状态。
  pkg节点下item表示每一项和应用相关的运行时权限。name是运行时权限名字。granted表示授予状态。flags表示该运行时权限的flag。
  shared-user 节点下item表示该shareuserid下的通用运行时权限状态。name是运行时权限名字。granted表示授予状态。flags表示该运行时权限的flag。

                                       ...                                                                                   

  每次更新,授予和移除权限都会触发回调。

frameworks/base/services/core/ava/com/android/server/pm/PackageManagerService.java

    private PermissionCallback mPermissionCallback = new PermissionCallback() {        @Override        public void onGidsChanged(int appId, int userId) {            mHandler.post(() -> killUid(appId, userId, KILL_APP_REASON_GIDS_CHANGED));        }        @Override        public void onPermissionGranted(int uid, int userId) {            mOnPermissionChangeListeners.onPermissionsChanged(uid);            // Not critical; if this is lost, the application has to request again.            synchronized (mPackages) {                mSettings.writeRuntimePermissionsForUserLPr(userId, false);            }        }        @Override        public void onInstallPermissionGranted() {            synchronized (mPackages) {                scheduleWriteSettingsLocked();            }        }        @Override        public void onPermissionRevoked(int uid, int userId) {            mOnPermissionChangeListeners.onPermissionsChanged(uid);            synchronized (mPackages) {                // Critical; after this call the application should never have the permission                mSettings.writeRuntimePermissionsForUserLPr(userId, true);            }            final int appId = UserHandle.getAppId(uid);            killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);        }        @Override        public void onInstallPermissionRevoked() {            synchronized (mPackages) {                scheduleWriteSettingsLocked();            }        }        @Override        public void onPermissionUpdated(int[] updatedUserIds, boolean sync) {            synchronized (mPackages) {                for (int userId : updatedUserIds) {                    mSettings.writeRuntimePermissionsForUserLPr(userId, sync);                }            }        }        @Override        public void onInstallPermissionUpdated() {            synchronized (mPackages) {                scheduleWriteSettingsLocked();            }        }        @Override        public void onPermissionRemoved() {            synchronized (mPackages) {                mSettings.writeLPr();            }        }    };

  安装权限被更新flag时会回调onInstallPermissionUpdated,从而执行PMS#scheduleWriteSettingsLocked–>Settings#writeLPr,从而更新/data/system/packages.xml。
  而运行时权限更新flag时会回调onPermissionUpdated,从而执行Settings#writeRuntimePermissionsForUserLPr-来更新data/system/users/{userid}/runtime-permissions.xml。

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

    private void updatePermissionFlags(String permName, String packageName, int flagMask,        ...        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);            }        }    }

  此外,运行时权限在授予或者移除时会分别回调onPermissionGranted和onPermissionRevoked,这两个函数也会更新data/system/users/{userid}/runtime-permissions.xml。安装权限在授予或者移除时没有回调。onInstallPermissionGranted和onInstallPermissionRevoked是在安全级别包含development级别的权限被授予或者移除时触发的,与一般的安装权限无关。

PMS扫描应用权限信息

  PMS开机扫描各个应用时,会根据AndroidManifest,xml的内容获得应用需要的权限,应用定义的权限等信息,保存到特定的数据结构里面。常用的几个权限相关的标签说明:
  uses-permission标签:声明应用需要使用到的权限。将权限的名称保存到PackageParser.Package的requestedPermissions集合中。

frameworks/base/core/ava/android/content/pm/PackageParser.java

    private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser)            throws XmlPullParserException, IOException {        TypedArray sa = res.obtainAttributes(parser,                com.android.internal.R.styleable.AndroidManifestUsesPermission);        // Note: don't allow this value to be a reference to a resource        // that may change.        String name = sa.getNonResourceString(                com.android.internal.R.styleable.AndroidManifestUsesPermission_name);        int maxSdkVersion = 0;        TypedValue val = sa.peekValue(                com.android.internal.R.styleable.AndroidManifestUsesPermission_maxSdkVersion);        if (val != null) {            if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) {                maxSdkVersion = val.data;            }        }        final String requiredFeature = sa.getNonConfigurationString(                com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredFeature, 0);        final String requiredNotfeature = sa.getNonConfigurationString(                com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredNotFeature, 0);        sa.recycle();        XmlUtils.skipCurrentTag(parser);        if (name == null) {            return true;        }        if ((maxSdkVersion != 0) && (maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT)) {            return true;        }        // Only allow requesting this permission if the platform supports the given feature.        if (requiredFeature != null && mCallback != null && !mCallback.hasFeature(requiredFeature)) {            return true;        }        // Only allow requesting this permission if the platform doesn't support the given feature.        if (requiredNotfeature != null && mCallback != null                && mCallback.hasFeature(requiredNotfeature)) {            return true;        }        int index = pkg.requestedPermissions.indexOf(name);        if (index == -1) {            pkg.requestedPermissions.add(name.intern());        } else {            Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "                    + name + " in package: " + pkg.packageName + " at: "                    + parser.getPositionDescription());        }        return true;    }

  permission标签:定义权限。name指定了权限的名称,protectionLevel指定了权限的保护等级,没有指定的话默认是Normal级别的。icon指定了权限图标。description 指明权限描述。label 指明权限标签。permissionGroup 为权限分组,方便将权限进行逻辑分组。backgroundPermission是对应的后台权限,name对应的则是前台权限,两者的关系后面会提到。permissionFlags指定了权限的flag。权限的信息保存在PermissionInfo中的结构中,后台权限和PermissionInfo保存在Permission中,所有Permission会被添加到PackageParser.Package的permissions集合中。

frameworks/base/core/ava/android/content/pm/PackageParser.java

    private boolean parsePermission(Package owner, Resources res,            XmlResourceParser parser, String[] outError)        throws XmlPullParserException, IOException {        TypedArray sa = res.obtainAttributes(parser,                com.android.internal.R.styleable.AndroidManifestPermission);        String backgroundPermission = null;        if (sa.hasValue(                com.android.internal.R.styleable.AndroidManifestPermission_backgroundPermission)) {            if ("android".equals(owner.packageName)) {                backgroundPermission = sa.getNonResourceString(                        com.android.internal.R.styleable                                .AndroidManifestPermission_backgroundPermission);            } else {                Slog.w(TAG, owner.packageName + " defines a background permission. Only the "                        + "'android' package can do that.");            }        }        Permission perm = new Permission(owner, backgroundPermission);        if (!parsePackageItemInfo(owner, perm.info, outError,                "", sa, true /*nameRequired*/,                com.android.internal.R.styleable.AndroidManifestPermission_name,                com.android.internal.R.styleable.AndroidManifestPermission_label,                com.android.internal.R.styleable.AndroidManifestPermission_icon,                com.android.internal.R.styleable.AndroidManifestPermission_roundIcon,                com.android.internal.R.styleable.AndroidManifestPermission_logo,                com.android.internal.R.styleable.AndroidManifestPermission_banner)) {            sa.recycle();            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;            return false;        }        // Note: don't allow this value to be a reference to a resource        // that may change.        perm.info.group = sa.getNonResourceString(                com.android.internal.R.styleable.AndroidManifestPermission_permissionGroup);        if (perm.info.group != null) {            perm.info.group = perm.info.group.intern();        }        perm.info.descriptionRes = sa.getResourceId(                com.android.internal.R.styleable.AndroidManifestPermission_description,                0);        perm.info.requestRes = sa.getResourceId(                com.android.internal.R.styleable.AndroidManifestPermission_request, 0);        perm.info.protectionLevel = sa.getInt(                com.android.internal.R.styleable.AndroidManifestPermission_protectionLevel,                PermissionInfo.PROTECTION_NORMAL);        perm.info.flags = sa.getInt(                com.android.internal.R.styleable.AndroidManifestPermission_permissionFlags, 0);        // For now only platform runtime permissions can be restricted        if (!perm.info.isRuntime() || !"android".equals(perm.info.packageName)) {            perm.info.flags &= ~PermissionInfo.FLAG_HARD_RESTRICTED;            perm.info.flags &= ~PermissionInfo.FLAG_SOFT_RESTRICTED;        } else {            // The platform does not get to specify conflicting permissions            if ((perm.info.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0                    && (perm.info.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0) {                throw new IllegalStateException("Permission cannot be both soft and hard"                        + " restricted: " + perm.info.name);            }        }        sa.recycle();        if (perm.info.protectionLevel == -1) {            outError[0] = " does not specify protectionLevel";            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;            return false;        }        perm.info.protectionLevel = PermissionInfo.fixProtectionLevel(perm.info.protectionLevel);        if (perm.info.getProtectionFlags() != 0) {            if ( (perm.info.protectionLevel&PermissionInfo.PROTECTION_FLAG_INSTANT) == 0                    && (perm.info.protectionLevel&PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) == 0                    && (perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE) !=                    PermissionInfo.PROTECTION_SIGNATURE) {                outError[0] = "  protectionLevel specifies a non-instant flag but is "                        + "not based on signature type";                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;                return false;            }        }        if (!parseAllMetaData(res, parser, "", perm, outError)) {            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;            return false;        }        owner.permissions.add(perm);        return true;    }

  permission-group标签:定义权限组。icon指定了权限组图标,label指定了权限组标签。description指定了权限组描述。request指定申请前台权限时显示的申请请求字符串。requestDetail指定了申请前台权限时的提示信息。backgroundRequest指定申请后台权限时显示的申请请求字符串。backgroundRequestDetail指定申请后台权限时的提示信息。目前使用了后台权限的前台权限有android.permission.ACCESS_FINE_LOCATION,android.permission.ACCESS_COARSE_LOCATION
这些位置相关权限。更多详细信息请参考Google官方说明:三态位置权限

frameworks/base/core/ava/android/content/pm/PackageParser.java

    private boolean parsePermissionGroup(Package owner, int flags, Resources res,            XmlResourceParser parser, String[] outError)            throws XmlPullParserException, IOException {        TypedArray sa = res.obtainAttributes(parser,                com.android.internal.R.styleable.AndroidManifestPermissionGroup);        int requestDetailResourceId = sa.getResourceId(                com.android.internal.R.styleable.AndroidManifestPermissionGroup_requestDetail, 0);        int backgroundRequestResourceId = sa.getResourceId(                com.android.internal.R.styleable.AndroidManifestPermissionGroup_backgroundRequest,                0);        int backgroundRequestDetailResourceId = sa.getResourceId(                com.android.internal.R.styleable                        .AndroidManifestPermissionGroup_backgroundRequestDetail, 0);        PermissionGroup perm = new PermissionGroup(owner, requestDetailResourceId,                backgroundRequestResourceId, backgroundRequestDetailResourceId);        if (!parsePackageItemInfo(owner, perm.info, outError,                "", sa, true /*nameRequired*/,                com.android.internal.R.styleable.AndroidManifestPermissionGroup_name,                com.android.internal.R.styleable.AndroidManifestPermissionGroup_label,                com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon,                com.android.internal.R.styleable.AndroidManifestPermissionGroup_roundIcon,                com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo,                com.android.internal.R.styleable.AndroidManifestPermissionGroup_banner)) {            sa.recycle();            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;            return false;        }        perm.info.descriptionRes = sa.getResourceId(                com.android.internal.R.styleable.AndroidManifestPermissionGroup_description,                0);        perm.info.requestRes = sa.getResourceId(                com.android.internal.R.styleable.AndroidManifestPermissionGroup_request, 0);        perm.info.flags = sa.getInt(                com.android.internal.R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags, 0);        perm.info.priority = sa.getInt(                com.android.internal.R.styleable.AndroidManifestPermissionGroup_priority, 0);        sa.recycle();        if (!parseAllMetaData(res, parser, "", perm,                outError)) {            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;            return false;        }        owner.permissionGroups.add(perm);        return true;    }

  permission-tree标签:permission-tree标签主要用于使用PackageManager#addPermission动态添加权限。permission-tree本身不声明权限,只是声明了一组权限的命名空间。使用PackageManager#addPermission的方法是:
  .AndroidManifest,xml声明一个permission-tree,name的名称是必须的,是要动态添加的权限名称的一个子字符串。当要动态添加的权限在系统中没有记录时,调用PackageManager#addPermission的应用UID要和定义permission-tree的应用UID一致。
  举个例子,一个应用在其AndroidManifest.xml声明了name为“com.example.foo”的permission-tree的节点,那么,该应用可以自由地使用PackageManager#addPermission添加名字带有“com.example.foo”的任意权限,例如“com.example.foo.FOR_EXAMPLE”,而且这些要添加的权限不需要在系统或者本应用中使用permission标签显式定义,如果要添加的权限名称在系统中曾经被使用过,那么它一定要是使用动态方法添加的权限,不然会报错:“Not allowed to modify non-dynamic permission xxx”。
  解析AndroidManifest,xml的permission-tree节点:
frameworks/base/core/java/android/content/pm/PackageParser.java

    private boolean parsePermissionTree(Package owner, Resources res,            XmlResourceParser parser, String[] outError)        throws XmlPullParserException, IOException {        Permission perm = new Permission(owner, (String) null);        TypedArray sa = res.obtainAttributes(parser,                com.android.internal.R.styleable.AndroidManifestPermissionTree);        if (!parsePackageItemInfo(owner, perm.info, outError,                "", sa, true /*nameRequired*/,                com.android.internal.R.styleable.AndroidManifestPermissionTree_name,                com.android.internal.R.styleable.AndroidManifestPermissionTree_label,                com.android.internal.R.styleable.AndroidManifestPermissionTree_icon,                com.android.internal.R.styleable.AndroidManifestPermissionTree_roundIcon,                com.android.internal.R.styleable.AndroidManifestPermissionTree_logo,                com.android.internal.R.styleable.AndroidManifestPermissionTree_banner)) {            sa.recycle();            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;            return false;        }        sa.recycle();        int index = perm.info.name.indexOf('.');        if (index > 0) {            index = perm.info.name.indexOf('.', index+1);        }        if (index < 0) {            outError[0] = " name has less than three segments: "                + perm.info.name;            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;            return false;        }        perm.info.descriptionRes = 0;        perm.info.requestRes = 0;        perm.info.protectionLevel = PermissionInfo.PROTECTION_NORMAL;        perm.tree = true;        if (!parseAllMetaData(res, parser, "", perm,                outError)) {            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;            return false;        }        owner.permissions.add(perm);        return true;    }

  动态添加权限的实现:

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

    private boolean addDynamicPermission(            PermissionInfo info, int callingUid, PermissionCallback callback) {        if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {            throw new SecurityException("Instant apps can't add permissions");        }        if (info.labelRes == 0 && info.nonLocalizedLabel == null) {            throw new SecurityException("Label must be specified in permission");        }        final BasePermission tree = mSettings.enforcePermissionTree(info.name, callingUid);//查找要动态添加的权限在系统中是否有记录        final boolean added;        final boolean changed;        synchronized (mLock) {            BasePermission bp = mSettings.getPermissionLocked(info.name);            added = bp == null;            int fixedLevel = PermissionInfo.fixProtectionLevel(info.protectionLevel);            if (added) {//没有记录                enforcePermissionCapLocked(info, tree);                bp = new BasePermission(info.name, tree.getSourcePackageName(),                        BasePermission.TYPE_DYNAMIC);            } else if (!bp.isDynamic()) {//不是动态添加的记录就报错                throw new SecurityException("Not allowed to modify non-dynamic permission "                        + info.name);            }            changed = bp.addToTree(fixedLevel, info, tree);//设置新添加权限的字段            if (added) {                mSettings.putPermissionLocked(info.name, bp);//添加到系统记录            }        }        if (changed && callback != null) {            callback.onPermissionChanged();        }        return added;    }

权限状态更新

  在包扫描的结尾阶段,都会有两步跟权限相关的操作:commitReconciledScanResultLocked和updateSettingsLI。
  commitReconciledScanResultLocked这一步会同步扫描得到的权限信息到PermissionManagerService,以向PermissionManagerService报告本次扫描的apk新增了哪些权限、权限树、权限组,然后让PermissionManagerService记录下来,这个在下章节Systemconfig/packages.xml/扫描包 权限区别会介绍到。
  updateSettingsLI这一步主要是根据扫描apk的结果改变apk的权限状态(PermissionsState)。

frameworks/base/services/core/ava/com/android/server/pm/PackageManagerService.java

    @GuardedBy("mPackages")    private void commitPackagesLocked(final CommitRequest request) {                ...                commitReconciledScanResultLocked(reconciledPkg);//第一步            updateSettingsLI(pkg, reconciledPkg.installArgs.installerPackageName, request.mAllUsers,                    res, reconciledPkg.installArgs.user, reconciledPkg.installArgs.installReason);//第二步                ...

  updateSettingsLI最终会调用到updateSettingsInternalLI,通过updatePermissions来更新权限状态。
frameworks/base/services/core/ava/com/android/server/pm/PackageManagerService.java

    private void updateSettingsInternalLI(PackageParser.Package pkg,            String installerPackageName, int[] allUsers, int[] installedForUsers,            PackageInstalledInfo res, UserHandle user, int installReason) {        ...        synchronized (mPackages) {// NOTE: This changes slightly to include UPDATE_PERMISSIONS_ALL regardless of the size of pkg.permissions            mPermissionManager.updatePermissions(pkg.packageName, pkg, true, mPackages.values(),                    mPermissionCallback);        ...

  最终会调用到PermissionManagerService#updatePermissions。该函数的第一个参数是要更新权限状态的包名,第二个参数是要更新权限状态的 PackageParser.Package,第三个参数是第二个参数对应的Volumn UUID,第四个参数的传入的flag,第五个参数是一个PackageParser.Package集合,一般是PMS记录的包集合,第六个参数是权限状态发生变化时的回调。
  flag参数会决定更新权限状态的策略。当带有UPDATE_PERMISSIONS_ALL标志位时,系统会尝试更新所有包的权限状态,这个通常发生在PermissionManagerService#updateAllPermissions调用时,在PackageManagerService.java构造函数扫描包动作结束后的一个点,PermissionManagerService#updateAllPermissions会被调用。当带有UPDATE_PERMISSIONS_REPLACE_PKG标志位时,系统会重置这个包的权限状态(PermissionSettings)再作修改,否则就会在原来的权限状态上作修改。UPDATE_PERMISSIONS_REPLACE_ALL标志位和UPDATE_PERMISSIONS_ALL搭配使用,表示既要更新所有包的权限状态,又要重置这些包的权限状态。

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

    private void updatePermissions(String changingPkgName, PackageParser.Package changingPkg,            String replaceVolumeUuid, int flags, Collection allPackages,            PermissionCallback callback) {        // TODO: Most of the methods exposing BasePermission internals [source package name,        // etc..] shouldn't be needed. Instead, when we've parsed a permission that doesn't        // have package settings, we should make note of it elsewhere [map between        // source package name and BasePermission] and cycle through that here. Then we        // define a single method on BasePermission that takes a PackageSetting, changing        // package name and a package.        // NOTE: With this approach, we also don't need to tree trees differently than        // normal permissions. Today, we need two separate loops because these BasePermission        // objects are stored separately.        // Make sure there are no dangling permission trees.        flags = updatePermissionTrees(changingPkgName, changingPkg, flags);        // Make sure all dynamic permissions have been assigned to a package,        // and make sure there are no dangling permissions.        flags = updatePermissions(changingPkgName, changingPkg, flags);        synchronized (mLock) {            if (mBackgroundPermissions == null) {                // Cache background -> foreground permission mapping.                // Only system declares background permissions, hence mapping does never change.                mBackgroundPermissions = new ArrayMap<>();                for (BasePermission bp : mSettings.getAllPermissionsLocked()) {                    if (bp.perm != null && bp.perm.info != null                            && bp.perm.info.backgroundPermission != null) {                        String fgPerm = bp.name;                        String bgPerm = bp.perm.info.backgroundPermission;                        List fgPerms = mBackgroundPermissions.get(bgPerm);                        if (fgPerms == null) {                            fgPerms = new ArrayList<>();                            mBackgroundPermissions.put(bgPerm, fgPerms);                        }                        fgPerms.add(fgPerm);                    }                }            }        }        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "restorePermissionState");        // Now update the permissions for all packages, in particular        // replace the granted permissions of the system packages.        if ((flags & UPDATE_PERMISSIONS_ALL) != 0) {//带有UPDATE_PERMISSIONS_ALL表示要更新所有包的权限状态,先把入参changingPkg以外的包权限状态更新            for (PackageParser.Package pkg : allPackages) {                if (pkg != changingPkg) {                    // Only replace for packages on requested volume                    final String volumeUuid = getVolumeUuidForPackage(pkg);                    final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_ALL) != 0)                            && Objects.equals(replaceVolumeUuid, volumeUuid);//带有UPDATE_PERMISSIONS_REPLACE_ALL表示当前处于安卓大版本升级后或者创建新用户的状态                    restorePermissionState(pkg, replace, changingPkgName, callback);                }            }        }        if (changingPkg != null) {//单独更新入参changingPkg包的权限状态            // Only replace for packages on requested volume            final String volumeUuid = getVolumeUuidForPackage(changingPkg);            final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_PKG) != 0)                    && Objects.equals(replaceVolumeUuid, volumeUuid);            restorePermissionState(changingPkg, replace, changingPkgName, callback);        }        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);    }

  restorePermissionState是更新权限状态的关键,参考代码中的注释:

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

    private void restorePermissionState(@NonNull PackageParser.Package 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) pkg.mExtras;        if (ps == null) {            return;        }        final PermissionsState permissionsState = ps.getPermissionsState();        PermissionsState origPermissions = permissionsState;        final int[] currentUserIds = UserManagerService.getInstance().getUserIds();        boolean runtimePermissionsRevoked = false;        int[] updatedUserIds = EMPTY_INT_ARRAY;        boolean changedInstallPermission = false;         //当带有UPDATE_PERMISSIONS_REPLACE_ALL或UPDATE_PERMISSIONS_REPLACE_PKG标志位时,replace为true。当包没有shareduserid时,重置权限状态。当包有shareduserid时,检测对应的SharedUserSetting的权限状态,如果发现SharedUserSetting授予了未被PermissionManagerService记录的权限(包括安装权限和运行时权限),则移除掉这些权限。        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(), UserManagerService.getInstance().getUserIds());                    if (!ArrayUtils.isEmpty(updatedUserIds)) {                        runtimePermissionsRevoked = true;                    }                }            }        }        permissionsState.setGlobalGids(mGlobalGids);        synchronized (mLock) {            ArraySet newImplicitPermissions = new ArraySet<>();            final int N = pkg.requestedPermissions.size();            for (int i = 0; i < N; i++) {               //遍历包中每一个使用uses-permission声明的权限                final String permName = pkg.requestedPermissions.get(i);                final BasePermission bp = mSettings.getPermissionLocked(permName);                final boolean appSupportsRuntimePermissions =                        pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M;                String upgradedActivityRecognitionPermission = null;                if (DEBUG_INSTALL) {                    Log.i(TAG, "Package " + pkg.packageName + " checking " + permName + ": " + bp);                }                if (bp == null || bp.getSourcePackageSetting() == null) {                    if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {                        if (DEBUG_PERMISSIONS) {                            Slog.i(TAG, "Unknown permission " + permName                                    + " in package " + pkg.packageName);                        }                    }                    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.implicitPermissions.contains(permName)                                || (permName.equals(Manifest.permission.ACTIVITY_RECOGNITION)))) {                    if (pkg.implicitPermissions.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 " + pkg.packageName);                        }                    } 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 permissionList =                                getSplitPermissions();                        int numSplitPerms = permissionList.size();                        for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {                            PermissionManager.SplitPermissionInfo 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 "                                            + pkg.packageName);                                }                                break;                            }                        }                    }                }                // Limit ephemeral apps to ephemeral allowed permissions.                if (pkg.applicationInfo.isInstantApp() && !bp.isInstant()) {                    if (DEBUG_PERMISSIONS) {                        Log.i(TAG, "Denying non-ephemeral permission " + bp.getName()                                + " for package " + pkg.packageName);                    }                    continue;                }                if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) {                    if (DEBUG_PERMISSIONS) {                        Log.i(TAG, "Denying runtime-only permission " + bp.getName()                                + " for package " + pkg.packageName);                    }                    continue;                }                final String perm = bp.getName();                boolean allowedSig = false;                int grant = GRANT_DENIED;                // Keep track of app op permissions.                if (bp.isAppOp()) {                    mSettings.addAppOpPackage(perm, pkg.packageName);                }                if (bp.isNormal()) {                    // For all apps normal permissions are install time ones.                    //对于应用申请的普通级别的权限,是直接授权的(GRANT_INSTALL)                    grant = GRANT_INSTALL;                } else if (bp.isRuntime()) {//对于运行时权限,如果以前是安装权限的现在变更为运行时权限的,视作升级(GRANT_UPGRADE)的授权方式;如果是普通的运行时权限,视作运行时(GRANT_RUNTIME)授权方式                    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()) {//对于签名级别的权限,如果签名校对成功,可直接授权(GRANT_INSTALL)                    // For all apps signature permissions are install time ones.                    allowedSig = grantSignaturePermission(perm, pkg, bp, origPermissions);                    if (allowedSig) {                        grant = GRANT_INSTALL;                    }                }                if (DEBUG_PERMISSIONS) {                    Slog.i(TAG, "Considering granting permission " + perm + " to package "                            + pkg.packageName);                }                if (grant != GRANT_DENIED) {                    if (!ps.isSystem() && ps.areInstallPermissionsFixed() && !bp.isRuntime()) {//对于1.非系统应用;2.非重置权限状态下;3.目标更改权限不是运行时权限;4.目标更改权限是安装权限或者是签名权限但是签名不匹配时;5.目前包没有对目标权限授权 这5种情况同时满足的情形下,拒绝授权。例如部分厂商手机OTA时会对data分区部分app做升级,新的app声明了一些以前版本没有声明过的安装权限,那系统会拒绝为这个新app自动授予这个安装权限                        // 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 : UserManagerService.getInstance().getUserIds()) {                                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 : currentUserIds) {                                // 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.                                //PermissionPolicyService是否已经初始化。PermissionPolicyService初始化后会针对限制权限作特殊处理,并且回调updateAllPermissions来重新设置权限状态。如果没有初始化,此处不必理会限制权限。                                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) {//app支持运行时权限                                    // If hard restricted we don't allow holding it                                    if (permissionPolicyInitialized && hardRestricted) {//PermissionPolicyService已经初始化而且变成的权限时硬性限制权限的情况下                                        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_REVOKE_ON_UPGRADE) != 0) {                                        flags &= ~FLAG_PERMISSION_REVOKE_ON_UPGRADE;                                        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) {//如果1.PermissionPolicyService未被初始化;2.目标权限不是硬性限制或者可以限制免除(影响限制权限在非限制免除的情况下不能被豁免) ;两种情况满足之一,且原来的权限状态是授予这个运行时权限的,新的权限状态也应该授予                                                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_REVOKE_ON_UPGRADE;                                                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.                                //如果PermissionPolicyService已经初始化,目标权限不是限制权限或者限制免除的情况下,移除掉目标权限的FLAG_PERMISSION_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 : currentUserIds) {                                // 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_REVOKE_ON_UPGRADE) != 0) {                                        flags &= ~FLAG_PERMISSION_REVOKE_ON_UPGRADE;                                        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.packageName)) {                                if (DEBUG_PERMISSIONS) {                                    Slog.i(TAG, "Not granting permission " + perm                                            + " to package " + pkg.packageName                                            + " 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;                        Slog.i(TAG, "Un-granting permission " + perm                                + " from package " + pkg.packageName                                + " (protectionLevel=" + bp.getProtectionLevel()                                + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)                                + ")");                    } 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.packageName))) {                            Slog.i(TAG, "Not granting permission " + perm                                    + " to package " + pkg.packageName                                    + " (protectionLevel=" + bp.getProtectionLevel()                                    + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)                                    + ")");                        }                    }                }            }            if ((changedInstallPermission || replace) && !ps.areInstallPermissionsFixed() &&                    !ps.isSystem() || ps.isUpdatedSystem()) {                // 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.packageName, userId);        }    }

Systemconfig/packages.xml/扫描包 权限区别

  Systemconfig能读取权限,packages.xml能读取权限,扫描包也可以读取权限,那这些权限有什么区别呢?
  Systemconfig定义的权限都是属于android这个包的,也就是系统权限,能够设置的权限属性比较少,常见的是通过group子标签设置一个gid。最终会记录到PermissionManagerService的mSettings(PermissionSettings)中。此外,SystemConfig不仅仅为权限服务,还有很多全局的系统配置都在里面实现。

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

    PermissionManagerService(Context context,            @NonNull Object externalLock) {        mContext = context;        mLock = externalLock;        mPackageManagerInt = LocalServices.getService(PackageManagerInternal.class);        mUserManagerInt = LocalServices.getService(UserManagerInternal.class);        mSettings = new PermissionSettings(mLock);        mHandlerThread = new ServiceThread(TAG,                Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);        mHandlerThread.start();        mHandler = new Handler(mHandlerThread.getLooper());        Watchdog.getInstance().addThread(mHandler);        mDefaultPermissionGrantPolicy = new DefaultPermissionGrantPolicy(                context, mHandlerThread.getLooper(), this);        SystemConfig systemConfig = SystemConfig.getInstance();        mSystemPermissions = systemConfig.getSystemPermissions();        mGlobalGids = systemConfig.getGlobalGids();        // propagate permission configuration        final ArrayMap permConfig =                SystemConfig.getInstance().getPermissions();        synchronized (mLock) {            for (int i=0; i

  而读取packages.xml的权限信息则是直接同步权限和权限树信息到PermissionManagerService的mSettings(PermissionSettings)中。packages.xml的权限信息来源于上一次关机时刻的权限信息,其来源于Systemconfig和扫描包得到的权限信息,本身不修改任何权限信息,只是帮助系统将权限记录(PermissionSettings)和状态(PermissionsState)初始化。
  如下所示,解析出来的权限信息会加入到Settings的mPermissions(PermissionSettings)中。

frameworks/base/services/core/java/com/android/server/pm/Settings.java

    boolean readLPw(@NonNull List users) {               ...                } else if (tagName.equals("permissions")) {                    mPermissions.readPermissions(parser);

  Settings的mPermissions和PermissionManagerService的mSettings是同一个,见下面代码。
  此外,packages.xml还提供了记录应用权限状态(PermissionState)的记录&恢复功能,
shareuserid状态(SharedUserSetting)的记录&恢复功能。

frameworks/base/services/core/ava/com/android/server/pm/PackageManagerService.java

    public PackageManagerService(Context context, Installer installer,        boolean factoryTest, boolean onlyCore) {        ...        // Create sub-components that provide services / data. Order here is important.        synchronized (mInstallLock) {        synchronized (mPackages) {            // Expose private service for system components to use.            LocalServices.addService(                    PackageManagerInternal.class, new PackageManagerInternalImpl());            sUserManager = new UserManagerService(context, this,                    new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages);            mComponentResolver = new ComponentResolver(sUserManager,                    LocalServices.getService(PackageManagerInternal.class),                    mPackages);            mPermissionManager = PermissionManagerService.create(context,                    mPackages /*externalLock*/);            mDefaultPermissionPolicy = mPermissionManager.getDefaultPermissionGrantPolicy();            mSettings = new Settings(Environment.getDataDirectory(),                    mPermissionManager.getPermissionSettings(), mPackages);//Settings的mPermissions和PermissionManagerService的mSettings是同一个        }

  扫描包得到的权限和权限树信息是记录在PackageParser.Package的permissions(ArrayList< Permission>)中,权限组信息是记录在PackageParser.Package的permissionGroups(ArrayList< PermissionGroup>)中。在每次扫描包的最后阶段(PMS#commitPackageSettings),系统会通过PMS#addAllPermissionGroups和PMS#addAllPermissions将PackageParser.Package包含的权限组和权限信息同步到PermissionManagerService的mSettings(PermissionSettings)中。

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

    private void addAllPermissions(PackageParser.Package pkg, boolean chatty) {        final int N = pkg.permissions.size();        for (int i=0; i Build.VERSION_CODES.LOLLIPOP_MR1) {                    p.group = mSettings.mPermissionGroups.get(p.info.group);                    // Warn for a permission in an unknown group.                    if (DEBUG_PERMISSIONS                            && p.info.group != null && p.group == null) {                        Slog.i(TAG, "Permission " + p.info.name + " from package "                                + p.info.packageName + " in an unknown group " + p.info.group);                    }                }                if (p.tree) {                    final BasePermission bp = BasePermission.createOrUpdate(                            mSettings.getPermissionTreeLocked(p.info.name), p, pkg,                            mSettings.getAllPermissionTreesLocked(), chatty);                    mSettings.putPermissionTreeLocked(p.info.name, bp);                } else {                    final BasePermission bp = BasePermission.createOrUpdate(                            mSettings.getPermissionLocked(p.info.name),                            p, pkg, mSettings.getAllPermissionTreesLocked(), chatty);                    mSettings.putPermissionLocked(p.info.name, bp);                }            }        }    }

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

    private void addAllPermissionGroups(PackageParser.Package pkg, boolean chatty) {        final int N = pkg.permissionGroups.size();        StringBuilder r = null;        for (int i=0; i

  相比Systemconfig,扫描包定义的权限可以包含更多的信息。例如可以定义所属权限组,图标,标签,描述,后台权限,安全等级等。以下是系统的AndroidManifest.xml定义的一个权限:

frameworks/base/core/res/AndroidManifest.xml

    

更多相关文章

  1. Android(安卓)- 判断当前网络环境、隐藏软键盘、动态监测及获取
  2. android Bundle saveInsanceState
  3. 安装 apk 到 /system/app 目录下
  4. Android中Junit测试、XML的序列化与解析
  5. ActivityManagerService架构剖析开篇
  6. Android(安卓)待机流程解析
  7. android沉浸式状态栏的问题解决
  8. Android学习笔记(五) Acticity跳转并传值
  9. Android(安卓)O 8.0及其以上系统的通知(Notification)、安装apk

随机推荐

  1. 对Android初学者学习中的几点建议
  2. android车载娱乐系统跟android平板的分析
  3. 深入Android(安卓)【一】 ―― 序及开篇
  4. Android状态栏和虚拟导航栏的适配总结
  5. Android省电策略
  6. Android(安卓)内存浅析【管理、机制、分
  7. android关于使用哪个版本开发的讨论
  8. [Android]Android(安卓)SDK 2.3与Eclipse
  9. 工程师淘金:开发Android主攻四大方向
  10. Android游戏可能遇到的3个问题及解决方案