Android学习心得(22) --- PackageManagerService源码解析platfrom.xml

新博客地址

blog.marssecure.com

platform.xml

Android中沿用Linux用户和组的来限制系统资源的访问,查看从Android真机pull出/etc/permissions/platform.xml
《Android学习心得(22) --- PackageManagerService源码解析platfrom.xml》

权限初始化

PackageManagerService构造函数会解析platform.xml,建立android权限和gid的对应关系。然后,扫描apk时,会由请求的权限找到对应的gid,并保存在Package类中。
由于Android很多都是使用permission来进行保护,需要在AndroidManifest中显示声明对应权限,有些在platfrom.xml中定义的权限须由特定用户组使用
下面来解析一下在该构造方法中对于plafrom.xml解析

源码分析

初始化处理permission文件

  • 创建的时候,在构造方法中初始化systemConfig
public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) {
...
    SystemConfig systemConfig = SystemConfig.getInstance()
...
}
  • getInstance()是创建一个SystemConfig对象
public static SystemConfig getInstance() {
        synchronized (SystemConfig.class) {
            if (sInstance == null) {
                sInstance = new SystemConfig();
            }
            return sInstance;
        }
 }
  • SystemConfig构造方法中,使用readPermissions处理了系统和OEM厂商的配置和系统权限
SystemConfig() {
 /system/etc/sysconfig
        readPermissions(Environment.buildPath(
                Environment.getRootDirectory(), "etc", "sysconfig"), false);
 /system/etc/permissions
        readPermissions(Environment.buildPath(
                Environment.getRootDirectory(), "etc", "permissions"), false);
 /oem/etc/sysconfig 
        readPermissions(Environment.buildPath(
                Environment.getOemDirectory(), "etc", "sysconfig"), true);
 /oem/etc/permissions
        readPermissions(Environment.buildPath( 
                Environment.getOemDirectory(), "etc", "permissions"), true);
 }
  • 对于上面四个目录都使用了readPermissions函数读取
void readPermissions(File libraryDir, boolean onlyFeatures) {
        // 从给定的文件夹中读取权限
 ....
        // 迭代方式读取xml文件
        File platformFile = null;
        for (File f : libraryDir.listFiles()) {
            // 最后单独处理platform.xml
            if (f.getPath().endsWith("etc/permissions/platform.xml")) {
                platformFile = f;
                continue;
            }
            ...
     // 取到的xml结尾的文件,使用readPermissionsFromXml读取
            readPermissionsFromXml(f, onlyFeatures);
        }
        // 最后读取平台权限以致其能最优先
        if (platformFile != null) {
            readPermissionsFromXml(platformFile, onlyFeatures);
        }
    }
  • 不管是platform.xml还是其他的xml文件,都是调用readPermissionsFromXml函数处理,assign-permission解析后存放到mSystemPermissions中,uid和permission对应
ArraySet<String> perms = mSystemPermissions.get(uid);
if (perms == null) {
        perms = new ArraySet<String>();
        mSystemPermissions.put(uid, perms);
 }
perms.add(perm);

permission将permission和gid存放到mPermissions中
PermissionEntry perm = mPermissions.get(name);
if (perm == null) {
    perm = new PermissionEntry(name);
    mPermissions.put(name, perm);
}
  • 整体方法源代码
private void readPermissionsFromXml(File permFile, boolean onlyFeatures) {
        FileReader permReader = null;
        permReader = new FileReader(permFile);
 // 当前系统是否对低内存支持
        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'");
            }

            while (true) {
                XmlUtils.nextElement(parser);
                String name = parser.getName();
                if ("group".equals(name) && !onlyFeatures) {
                    String gidStr = parser.getAttributeValue(null, "gid");
                    if (gidStr != null) {
                        int gid = android.os.Process.getGidForName(gidStr);
                        mGlobalGids = appendInt(mGlobalGids, gid);
                    } else {
                        Slog.w(TAG, "<group> without gid in " + permFile + " at "
                                + parser.getPositionDescription());
                    }

                    XmlUtils.skipCurrentTag(parser);
                    continue;

                } else if ("permission".equals(name) && !onlyFeatures) {
                    String perm = parser.getAttributeValue(null, "name");
                    perm = perm.intern();
                    readPermission(parser, perm);

                } else if ("assign-permission".equals(name) && !onlyFeatures) {
                    String perm = parser.getAttributeValue(null, "name");
                    String uidStr = parser.getAttributeValue(null, "uid");
                    int uid = Process.getUidForName(uidStr);
                    perm = perm.intern();
                    ArraySet<String> perms = mSystemPermissions.get(uid);
                    if (perms == null) {
                        perms = new ArraySet<String>();
                        mSystemPermissions.put(uid, perms);
                    }
                    perms.add(perm);
                    XmlUtils.skipCurrentTag(parser);

                } else if ("library".equals(name) && !onlyFeatures) {
                    String lname = parser.getAttributeValue(null, "name");
                    String lfile = parser.getAttributeValue(null, "file");
                    if (lname == null) {
                        Slog.w(TAG, "<library> without name in " + permFile + " at "
                                + parser.getPositionDescription());
                    } else if (lfile == null) {
                        Slog.w(TAG, "<library> without file in " + permFile + " at "
                                + parser.getPositionDescription());
                    } else {
                        //Log.i(TAG, "Got library " + lname + " in " + lfile);
                        mSharedLibraries.put(lname, lfile);
                    }
                    XmlUtils.skipCurrentTag(parser);
                    continue;

                } else if ("feature".equals(name)) {
                    String fname = parser.getAttributeValue(null, "name");
                    boolean allowed;
                    if (!lowRam) {
                        allowed = true;
                    } else {
                        String notLowRam = parser.getAttributeValue(null, "notLowRam");
                        allowed = !"true".equals(notLowRam);
                    }
                    if (fname == null) {
                        Slog.w(TAG, "<feature> without name in " + permFile + " at "
                                + parser.getPositionDescription());
                    } else if (allowed) {
                        //Log.i(TAG, "Got feature " + fname);
                        FeatureInfo fi = new FeatureInfo();
                        fi.name = fname;
                        mAvailableFeatures.put(fname, fi);
                    }
                    XmlUtils.skipCurrentTag(parser);
                    continue;

                } else if ("unavailable-feature".equals(name)) {
                    String fname = parser.getAttributeValue(null, "name");
                    if (fname == null) {
                        Slog.w(TAG, "<unavailable-feature> without name in " + permFile + " at "
                                + parser.getPositionDescription());
                    } else {
                        mUnavailableFeatures.add(fname);
                    }
                    XmlUtils.skipCurrentTag(parser);
                    continue;

                } else if ("allow-in-power-save".equals(name) && !onlyFeatures) {
                    String pkgname = parser.getAttributeValue(null, "package");
                    if (pkgname == null) {
                        Slog.w(TAG, "<allow-in-power-save> without package in " + permFile + " at "
                                + parser.getPositionDescription());
                    } else {
                        mAllowInPowerSave.add(pkgname);
                    }
                    XmlUtils.skipCurrentTag(parser);
                    continue;

                } else if ("fixed-ime-app".equals(name) && !onlyFeatures) {
                    String pkgname = parser.getAttributeValue(null, "package");
                    if (pkgname == null) {
                        Slog.w(TAG, "<fixed-ime-app> without package in " + permFile + " at "
                                + parser.getPositionDescription());
                    } else {
                        mFixedImeApps.add(pkgname);
                    }
                    XmlUtils.skipCurrentTag(parser);
                    continue;

                } else {
                    XmlUtils.skipCurrentTag(parser);
                    continue;
                }
            }
        } catch (XmlPullParserException e) {
           ...
        } finally {
            IoUtils.closeQuietly(permReader);
        }

        for (String fname : mUnavailableFeatures) {
            if (mAvailableFeatures.remove(fname) != null) {
                Slog.d(TAG, "Removed unavailable feature " + fname);
            }
        }
    }
  • 看platfrom.xml文件中内容,permission将属性name中权限赋予group中gid用户组,assign-permission把属性name中权限赋予uid用户
<permissions>
    <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.INTERNET" >
        <group gid="inet" />
    </permission>
    ...
    <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" />
    <library name="android.test.runner" file="/system/framework/android.test.runner.jar" />
    <library name="javax.obex" file="/system/framework/javax.obex.jar"/>
    <library name="javax.btobex" file="/system/framework/javax.btobex.jar"/>
    <!--网络访问的白名单,即使他们不在前面-->
    <allow-in-power-save package="com.android.providers.downloads" />
</permissions>

未来:

下一步会去研究一下安装apk时候权限解析的源代码,更好理解权限在整个系统中的运用。希望对大家有所帮助,也希望你可以一直支持我们MarsSecure。

    原文作者:qiyu93422
    原文地址: https://blog.csdn.net/qiyu93422/article/details/52843007
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞