PackageManagerService(Android5.1)深入分析(二)处理permission文件

PackageManagerService的构造函数中,调用了SystemConfig的getSystemPermissions方法来获取系统的permission列表。

下面我们就分析下如何从系统文件中获取permission。


一、分析构造SystemConfig构造函数

我们先来分析下SystemConfig类的构造函数

    SystemConfig() {
        // Read configuration from system
        readPermissions(Environment.buildPath(
                Environment.getRootDirectory(), "etc", "sysconfig"), false);
        // Read configuration from the old permissions dir
        readPermissions(Environment.buildPath(
                Environment.getRootDirectory(), "etc", "permissions"), false);
        // Only read features from OEM config
        readPermissions(Environment.buildPath(
                Environment.getOemDirectory(), "etc", "sysconfig"), true);
        readPermissions(Environment.buildPath(
                Environment.getOemDirectory(), "etc", "permissions"), true);
    }

Environment.getRootDirectory方法代表的是system目录,我们再来看看Environment.buildPath方法

    public static File buildPath(File base, String... segments) {
        File cur = base;
        for (String segment : segments) {
            if (cur == null) {
                cur = new File(segment);
            } else {
                cur = new File(cur, segment);
            }
        }
        return cur;
    }

这个方法其实就是一层一层建文件,因此第一个文件就是system/etc/sysconfig 而第二个就是system/etc/permissions下面两个oem的就一样了。而我们手机中system/etc/sysconfig 这个目录是不存在的,因此只需分析permissions目录了。


二、xml文件

我们先来看android.hardware.wifi.xml,就是一个feature,而且大部分的文件都是这样的,除了platform.xml

<permissions>
    <feature name="android.hardware.wifi" />
</permissions>

下面就手机我们看下system/etc/permissions下的platform.xml文件

<permissions>

    <!-- ================================================================== -->
    <!-- ================================================================== -->
    <!-- ================================================================== -->

    <!-- The following tags are associating low-level group IDs with
         permission names.  By specifying such a mapping, you are saying
         that any application process granted the given permission will
         also be running with the given group ID attached to its process,
         so it can perform any filesystem (read, write, execute) operations
         allowed for that group. -->

    <permission name="android.permission.BLUETOOTH_ADMIN" >
        <group gid="net_bt_admin" />
    </permission>

    <permission name="android.permission.BLUETOOTH" >
        <group gid="net_bt" />
    </permission>

    <permission name="android.permission.BLUETOOTH_STACK" >
        <group gid="net_bt_stack" />
    </permission>

    <permission name="android.permission.NET_TUNNELING" >
        <group gid="vpn" />
    </permission>

    <permission name="android.permission.INTERNET" >
        <group gid="inet" />
    </permission>

    <permission name="android.permission.READ_LOGS" >
        <group gid="log" />
    </permission>

    <permission name="android.permission.WRITE_MEDIA_STORAGE" >
        <group gid="media_rw" />
        <group gid="sdcard_rw" />
    </permission>

    <permission name="android.permission.ACCESS_MTP" >
        <group gid="mtp" />
    </permission>

    <permission name="android.permission.NET_ADMIN" >
        <group gid="net_admin" />
    </permission>

    <!-- The group that /cache belongs to, linked to the permission
         set on the applications that can access /cache -->
    <permission name="android.permission.ACCESS_CACHE_FILESYSTEM" >
        <group gid="cache" />
    </permission>

    <!-- RW permissions to any system resources owned by group 'diag'.
         This is for carrier and manufacture diagnostics tools that must be
         installable from the framework. Be careful. -->
    <permission name="android.permission.DIAGNOSTIC" >
        <group gid="input" />
        <group gid="diag" />
    </permission>

    <!-- Group that can read detailed network usage statistics -->
    <permission name="android.permission.READ_NETWORK_USAGE_HISTORY">
        <group gid="net_bw_stats" />
    </permission>

    <!-- Group that can modify how network statistics are accounted -->
    <permission name="android.permission.MODIFY_NETWORK_ACCOUNTING">
        <group gid="net_bw_acct" />
    </permission>

    <permission name="android.permission.LOOP_RADIO" >
        <group gid="loop_radio" />
    </permission>

    <!-- Hotword training apps sometimes need a GID to talk with low-level
         hardware; give them audio for now until full HAL support is added. -->
    <permission name="android.permission.MANAGE_VOICE_KEYPHRASES">
        <group gid="audio" />
    </permission>

    <permission name="android.permission.ACCESS_FM_RADIO" >
        <group gid="media" />
    </permission>

    <!-- ================================================================== -->
    <!-- ================================================================== -->
    <!-- ================================================================== -->

    <!-- The following tags are assigning high-level permissions to specific
         user IDs.  These are used to allow specific core system users to
         perform the given operations with the higher-level framework.  For
         example, we give a wide variety of permissions to the shell user
         since that is the user the adb shell runs under and developers and
         others should have a fairly open environment in which to
         interact with the system. -->

    <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
    <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="media" />
    <assign-permission name="android.permission.WAKE_LOCK" uid="media" />
    <assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="media" />
    <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="media" />

    <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />

    <!-- This is a list of all the libraries available for application
         code to link against. -->

    <library name="android.test.runner"
            file="/system/framework/android.test.runner.jar" />
    <library name="javax.obex"
            file="/system/framework/javax.obex.jar" />
    <library name="org.apache.http.legacy"
            file="/system/framework/org.apache.http.legacy.jar" />

    <!-- These are the standard packages that are white-listed to always have internet
         access while in power save mode, even if they aren't in the foreground. -->
    <allow-in-power-save-except-idle package="com.android.providers.downloads" />

</permissions>


platform.xml主要由3块组成:

1. <permission>把属性name中的字符串表示的权限(permission)赋予<group>标签中的属性gid中的用户组

2.<assign-permission>把属性name中的字符串表示的权限(permission)赋予<group>标签中的属性uid中的用户

3.<library>表示除了framework中的动态库以外,系统将为应用自动加载的动态库。


而解析出来这些标签又放在哪呢?

1.标签<permission>中的属性name字符串和<group>标签中的gid都放到了变量mSettings的mPermissions中

2.所有的gid放在mGlobalGids中

3.标签<assign-permission>的内容放到PackageManagerService的成员变量mSystemPermission中。

mSystemPermission是放在下面这样一个数据结构中

final SparseArray<ArraySet<String>> mSystemPermissions = new SparseArray<>();
我们再看看它是如何操作的

                    ArraySet<String> perms = mSystemPermissions.get(uid);
                    if (perms == null) {
                        perms = new ArraySet<String>();
                        mSystemPermissions.put(uid, perms);
                    }
                    perms.add(perm);

4.<library>动态库放在mSharedLibraries

5.<feature>放在mAvailableFeatures中。

Android的很多功能是通过所谓的permission字符串来保护的,应用如果要使用某项权限,就要在AndroidManifest.xml显示的加上permission字符串。但是有些功能只能由特定用户组的应用使用,在platform.xml定义的就是这种限制规则。



下面我们再来看看核心函数readPermissions():

void readPermissions(File libraryDir, boolean onlyFeatures) {
        // Read permissions from given directory.
        if (!libraryDir.exists() || !libraryDir.isDirectory()) {// 不是一个目录或者不存在
            if (!onlyFeatures) {
                Slog.w(TAG, "No directory " + libraryDir + ", skipping");
            }
            return;
        }
        if (!libraryDir.canRead()) {
            Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
            return;
        }

        // Iterate over the files in the directory and scan .xml files
        File platformFile = null;
        for (File f : libraryDir.listFiles()) {
            // We'll read platform.xml last
            if (f.getPath().endsWith("etc/permissions/platform.xml")) {
                platformFile = f;//先不处理platform.xml
                continue;
            }

            if (!f.getPath().endsWith(".xml")) {
                Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
                continue;
            }
            if (!f.canRead()) {
                Slog.w(TAG, "Permissions library file " + f + " cannot be read");
                continue;
            }

            readPermissionsFromXml(f, onlyFeatures);
        }

        // Read platform permissions last so it will take precedence
        if (platformFile != null) {//这边再来处理platform.xml
            readPermissionsFromXml(platformFile, onlyFeatures);
        }
    }


然后就readPermissionsFromXml读取各个标签放在各个成员变量中。


我们最后再来看下Permission标签的解析:

    void readPermission(XmlPullParser parser, String name)
            throws IOException, XmlPullParserException {

        name = name.intern();

        PermissionEntry perm = mPermissions.get(name);
        if (perm == null) {
            perm = new PermissionEntry(name);
            mPermissions.put(name, perm);
        }
        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 ("group".equals(tagName)) {
                String gidStr = parser.getAttributeValue(null, "gid");
                if (gidStr != null) {
                    int gid = Process.getGidForName(gidStr);
                    perm.gids = appendInt(perm.gids, gid);//放gid
                } else {
                    Slog.w(TAG, "<group> without gid at "
                            + parser.getPositionDescription());
                }
            }
            XmlUtils.skipCurrentTag(parser);
        }
    }

上面其中    final ArrayMap<String, PermissionEntry> mPermissions = new ArrayMap<>();  mPermissions是个map,权限的name对应是map的key,然后每个PermissionEntry 放入各个gid。


这节结束了,至于应用如何获取权限,后续分析


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值