PackageManagerService之app数据类(Settings)分析

PMS系列:
1、PackageManagerService服务框架详解
2、PackageManagerService启动分析
3、本文PackageManagerService之app数据类(Settings)分析
4、PackageManagerService扫描安装apk详解
5、PackageManagerService根据权限等级管理权限(默认赋予apk权限)

从PMS的初始化分析,我们知道了PMS中的这个Settings类是用来保存apk的信息
本文主要分析这个Settings类,(frameworks\base\services\core\java\com\android\server\pm\Settings.java)
本文主线是PackageManagerService.java构造函数中,按PMS的调用mSettings的顺序来分析Settings类,以了解Settings主要存了什么

一、new Settings

在PackageManagerService.java构造函数中开始定义Settings

final ArrayMap<String, PackageParser.Package> mPackages = new ArrayMap<String, PackageParser.Package>();
mSettings = new Settings(mPackages);

创建

Settings(Object lock) {
        this(Environment.getDataDirectory(), lock); //Environment.getDataDirectory() "/data"
    }

    Settings(File dataDir, Object lock) {
        mLock = lock;
    //给data目录权限
        mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);
    //创建data/system目录
        mSystemDir = new File(dataDir, "system");
        mSystemDir.mkdirs();
    //给mSystemDir设置权限
        FileUtils.setPermissions(mSystemDir.toString(),
                FileUtils.S_IRWXU|FileUtils.S_IRWXG
                |FileUtils.S_IROTH|FileUtils.S_IXOTH,
                -1, -1);
    //packages-backup.xml是packages.xml的备份,当apk信息写入backup完成后,再创建packages.xml以免数据丢失
        mSettingsFilename = new File(mSystemDir, "packages.xml");
        mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
    //packages.list保存系统中存在的所有非系统自带的APK信息
        mPackageListFilename = new File(mSystemDir, "packages.list");
        FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);

    //sdcardfs相关
        final File kernelDir = new File("/config/sdcardfs");
        mKernelMappingFilename = kernelDir.exists() ? kernelDir : null;
        
    //packages-stopped.xml用于描述系统中强行停止运行的package信息,backup也是备份文件
        mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
        mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
    }

二、addSharedUserLPw

继续看PackageManagerService

mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);

我们来看Settings类的添加uid的方法

//name和uid对应 "android.uid.system", Process.SYSTEM_UID(1000)
//pkgFlags均为:ApplicationInfo.FLAG_SYSTEM表示系统包内应用
//pkgPrivateFlags均为ApplicationInfo.PRIVATE_FLAG_PRIVILEGED,可以拥有特殊权限
//保存到mSharedUsers
SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {
        SharedUserSetting s = mSharedUsers.get(name);
        if (s != null) {
            if (s.userId == uid) {
                return s;
            }
            PackageManagerService.reportSettingsProblem(Log.ERROR,
                    "Adding duplicate shared user, keeping first: " + name);
            return null;
        }
    //根据参数构建SharedUserSetting
        s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
        s.userId = uid;
        if (addUserIdLPw(uid, s, name)) {
        //按name和s,存入map中
            mSharedUsers.put(name, s);
            return s;
        }
        return null;
    }

//最后被保存到了mUserIds和mOtherUserIds中
//addUserIdLPw在getPackageLPw也有调用
private boolean addUserIdLPw(int uid, Object obj, Object name) {
        if (uid > Process.LAST_APPLICATION_UID) {//最大19999
            return false;
        }
    //FIRST_APPLICATION_UID = 10000普通的id,即应用程序从10000开始,10000以下是系统进程id
        if (uid >= Process.FIRST_APPLICATION_UID) {
            int N = mUserIds.size();
            final int index = uid - Process.FIRST_APPLICATION_UID;
            while (index >= N) {
                mUserIds.add(null);
                N++;
            }
            if (mUserIds.get(index) != null) {
                PackageManagerService.reportSettingsProblem(Log.ERROR,
                        "Adding duplicate user id: " + uid
                        + " name=" + name);
                return false;
            }
        //保存
            mUserIds.set(index, obj);
        } else {
            if (mOtherUserIds.get(uid) != null) {
                PackageManagerService.reportSettingsProblem(Log.ERROR,
                        "Adding duplicate shared id: " + uid
                                + " name=" + name);
                return false;
            }
        //保存
            mOtherUserIds.put(uid, obj);
        }
        return true;
    }

mSharedUsers(map)以name为索引管理SharedUserSetting
mUserIds(ArrayList)以uid为索引管理SharedUserSettings,mUserIds保存了系统中已经分配的uid对应的SharedUserSetting结构。每次分配时总是从第一个开始轮询,找到第一个空闲的位置i,然后加上FIRST_APPLICATION_UID即可
mOtherUserIds(SparseArray)以uid为索引管理SharedUserSettings
接下来看看SharedUserSettings

final class SharedUserSetting extends SettingBase {
    final String name;
    int userId;
    int uidFlags;
    int uidPrivateFlags;

    final ArraySet<PackageSetting> packages = new ArraySet<PackageSetting>();

    final PackageSignatures signatures = new PackageSignatures();

    SharedUserSetting(String _name, int _pkgFlags, int _pkgPrivateFlags) {
        super(_pkgFlags, _pkgPrivateFlags);
        uidFlags =  _pkgFlags;
        uidPrivateFlags = _pkgPrivateFlags;
        name = _name;
    }

    void removePackage(PackageSetting packageSetting) {
        if (packages.remove(packageSetting)) {
           ...
        }
    }

    void addPackage(PackageSetting packageSetting) {
        if (packages.add(packageSetting)) {
            ...
        }
    }
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
    package="com.android.settings"
    coreApp="true"
    //指定sharedUserId,PKMS会为其创建了SharedUserSettings
    android:sharedUserId="android.uid.system"/>

1.如果在 AndroidManifest.xml 中指定了sharedUserId,那么先查看全局list中(mSharedUsers)是否该uid对应的SharedUserSetting数据结构,若没有则新分配一个uid,创建 SharedUserSetting 并保存到全局全局 list(mSharedUsers)中
2.SharedUserSetting继承自SettingBase,SettingBase持有PermissionsState对象,用于表示可用的权限
3.PackageSettings中持有的是单个Package独有的权限
4.SharedUserSettings中持有的是一组Package共有的权限
5.SharedUserSetting将PackageSettings添加到packages(ArraySet<PackageSetting>)中,表示PackageSetting为其中的共享者。所以相同的sharedUserId运行到同一uid并可以数据共享

三、mSettings.mPermissions

SystemConfig systemConfig = SystemConfig.getInstance();
ArrayMap<String, SystemConfig.PermissionEntry> permConfig
                    = systemConfig.getPermissions();
for (int i=0; i<permConfig.size(); i++) {
    SystemConfig.PermissionEntry perm = permConfig.valueAt(i);
    BasePermission bp = mSettings.mPermissions.get(perm.name);
if (bp == null) {
    bp = new BasePermission(perm.name, "android", BasePermission.TYPE_BUILTIN);
    mSettings.mPermissions.put(perm.name, bp);
}
if (perm.gids != null) {
    bp.setGids(perm.gids, perm.perUser);
}
}

1、先看systemConfig是什么

public static SystemConfig getInstance() {
    ...
    sInstance = new SystemConfig();
    ....
}
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);
        // Allow ODM to customize system configs around libs, features and apps
        int odmPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_APP_CONFIGS;
        readPermissions(Environment.buildPath(
                Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);
        readPermissions(Environment.buildPath(
                Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);
        // Only allow OEM to customize features
        readPermissions(Environment.buildPath(
                Environment.getOemDirectory(), "etc", "sysconfig"), ALLOW_FEATURES);
        readPermissions(Environment.buildPath(
                Environment.getOemDirectory(), "etc", "permissions"), ALLOW_FEATURES);

        /// M: Only allow libraries
        readPermissions(Environment.buildPath(
                Environment.getVendorDirectory(), "etc", "sysconfig"), ALLOW_LIBS);
        readPermissions(Environment.buildPath(
                Environment.getVendorDirectory(), "etc", "permissions"), ALLOW_LIBS);
    }

读取/etc目录下sysconfig、permissions…等的xml权限文件,最后保存到mPermissions
2.for (int i=0; i<permConfig.size(); i++)
遍历,将android权限与gid关联

四、readLPw()

readLPw:解析packages.xml、packages-stopped.xml

mRestoredSettings = mSettings.readLPw(sUserManager.getUsers(false));
 boolean readLPw(@NonNull List<UserInfo> users) {
        ...
        //解析xml,其中很多read方法,都是解析对应tag的
    int outerDepth = parser.getDepth();
    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("package")) {
        readPackageLPw(parser);
    } else if (tagName.equals("permissions")) {
        readPermissionsLPw(mPermissions, parser);
    } else if (tagName.equals("permission-trees")) {
        readPermissionsLPw(mPermissionTrees, parser);
    } else if (tagName.equals("shared-user")) {
        readSharedUserLPw(parser);
    } else if (tagName.equals("preferred-packages")) {
        // no longer used.
    } 
    ...

五、mSettings.writeLPr();

将安装信息写回pakcage.xml

void writeLPr() {
    ...
        //都是一些xml操作
        try {
            FileOutputStream fstr = new FileOutputStream(mSettingsFilename);
            BufferedOutputStream str = new BufferedOutputStream(fstr);

            //XmlSerializer serializer = XmlUtils.serializerInstance();
            XmlSerializer serializer = new FastXmlSerializer();
            serializer.setOutput(str, StandardCharsets.UTF_8.name());
            serializer.startDocument(null, true);
            serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
        //开始的tag
            serializer.startTag(null, "packages");

            for (int i = 0; i < mVersion.size(); i++) {
                final String volumeUuid = mVersion.keyAt(i);
                final VersionInfo ver = mVersion.valueAt(i);
        //TAG:version
                serializer.startTag(null, TAG_VERSION);
                XmlUtils.writeStringAttribute(serializer, ATTR_VOLUME_UUID, volumeUuid);
                XmlUtils.writeIntAttribute(serializer, ATTR_SDK_VERSION, ver.sdkVersion);
                XmlUtils.writeIntAttribute(serializer, ATTR_DATABASE_VERSION, ver.databaseVersion);
                XmlUtils.writeStringAttribute(serializer, ATTR_FINGERPRINT, ver.fingerprint);
                serializer.endTag(null, TAG_VERSION);
            }
        //TAG:verifier
            if (mVerifierDeviceIdentity != null) {
                serializer.startTag(null, "verifier");
                serializer.attribute(null, "device", mVerifierDeviceIdentity.toString());
                serializer.endTag(null, "verifier");
            }
        //等等各种数据
            ...

            //结TAG
            serializer.endTag(null, "packages");

            serializer.endDocument();

            str.flush();
            FileUtils.sync(fstr);
            str.close();

            //重新设置权限
            mBackupSettingsFilename.delete();
            FileUtils.setPermissions(mSettingsFilename.toString(),
                    FileUtils.S_IRUSR|FileUtils.S_IWUSR
                    |FileUtils.S_IRGRP|FileUtils.S_IWGRP,
                    -1, -1);
        //刷新packagelist等数据
            writeKernelMappingLPr();
            writePackageListLPr();
            writeAllUsersPackageRestrictionsLPr();
            writeAllRuntimePermissionsLPr();
            return;

        ...
    }

小结

本文根据PMS初始化时候调用的Settings相关方法对,Settings类初步分析:
1、Settings:创建package.xml、packages-stopped.xml等
2、addSharedUserLPw:添加SharedUserSettings数据结构
3、mSettings.mPermissions:权限数据读取
4、readLPw():读取packag.xml
5、writeLPr():写入已安装apk信息到packag.xml

Read the fucking sources code!

    原文作者:Yink_Liu
    原文地址: https://www.jianshu.com/p/e19110ccc3f9
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞