pms解析--未完待续

pms 即PackageManagerService,有的朋友也喜欢叫他pkms,但是正常的叫法当然是pms啦,如果有较真的同学不要喷我哦

那么现在就开始介绍下这个Framework(java类库)级别的服务吧!

阅读本文章可能要花费30分钟时间,做好准备

一、概述

pms他对于android系统来是一个很重要的角色,他负责任何一个app装入一台安卓手机的各个过程,可以戏称他为安卓手机管理app的一个大管家,

pms顾名思义,他是管理着所有package 的信息,比如package的安装、卸载、更新替换、读取清单文件,将清单文件解析成的数据结构提供给其他的

系统服务去,这些其他的系统服务如ams。

二、pms的启动过程

我们知道,安卓手机开机的时候最早开启的系统服务有两个,一个是ServiceManager,一个是zogyte,而这个ServiceManager在创建完成之后他内部维护了一个表,

后期开启的服务都会在ServiceManager这个表中体现出来,而zogyte这个服务会为新开启的服务clone一份空间,供新服务启动

那么首先,pms会在SystemServer中被初始化出来

方法大致是:

pm=PackageManagerService.main(context,installer,factoryTest!=SystemServer.FACTORY_TEST_OFF.onlyCore);

即pms的实例化方法就是这个main方法,那么现在我们来看一下这个main方法

public static final IPackageManager main(Context context, Installer installer,  
        boolean factoryTest, boolean onlyCore) {  
    PackageManagerService m = new PackageManagerService(context, installer,  
            factoryTest, onlyCore);  
    ServiceManager.addService("package", m);  
    return m;  
}

不难看出,main方法中调用了他自己的构造方法,并且我们看到,在调用构造方法之后,servicemanager还对此service作了一个类似注册的动作。

我们现在来分析下这个构造方法,第一个参数是上下文,没得说的,第二个参数是一个Installer对象,这个对象在后期会和Installd这个进行通信,第三个参数是

一个boolean,意思是“是否为出厂测试”,那么我们正常的手机肯定不是呀,所以这里默认是false,第四个参数是onlycore,这个onlycore与vold有关系,这个后面在做介绍,大家

只需要知道这默认就是false就可以了。

我们现在看一下pms的部分构造方法:

public PackageManagerService(Context context, Installer installer,  
        boolean factoryTest, boolean onlyCore) {  
  
    mContext = context;  
    mFactoryTest = factoryTest;  
    mOnlyCore = onlyCore;  
    mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));  
    mMetrics = new DisplayMetrics();  
    mSettings = new Settings(context);  
    mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,  
            ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);  
    mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,  
            ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);  
    mSettings.addSharedUserLPw("android.uid.log", LOG_UID,  
            ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);  
    mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,  
            ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);  
    mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,  
            ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);  
    mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,  
            ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED); 

这一部分,就是做了一些复制操作,上边已经介绍过

factoryTest和onlycore,这先不说了,

我们来看mNoDexOpt这个值,这个值是一个boolean类型的,后边的值得意思是判断是否是eng版本的,eng是engineer的缩写,

后边的SystemProperties.get(“ro.build.type)拿到的就是当前手机是属于用户版(返回值是“user”)还是调试版(返回值是“eng”),这一般是返回false的。

mMetrics即手机的屏幕尺寸

下边这个Settings很重要,大家要划重点:

他是android的全局管理者,用来协助pms保存所有的安装包信息

在pms的构造方法中,我们看到settings一直在调用addSharedUserLPw方法,那这个方法其实就是把SharedUserId的名字和他对应的UID对应写到settings当中

而这个SharedUserId他是跟app安装有很大关系的。

我们来看一下settings的构造方法

Settings(Context context) {  
    this(context, Environment.getDataDirectory());  
}  
  
Settings(Context context, File dataDir) {  
    mContext = context;  
    mSystemDir = new File(dataDir, "system");  
    mSystemDir.mkdirs();  
    FileUtils.setPermissions(mSystemDir.toString(),  
            FileUtils.S_IRWXU|FileUtils.S_IRWXG  
            |FileUtils.S_IROTH|FileUtils.S_IXOTH,  
            -1, -1);  
    mSettingsFilename = new File(mSystemDir, "packages.xml");  
    mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");  
    mPackageListFilename = new File(mSystemDir, "packages.list");  
    FileUtils.setPermissions(mPackageListFilename, 0660, SYSTEM_UID, PACKAGE_INFO_GID);  
  
    mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");  
    mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");  
}  

ok,setting的构造方法也很简单,大体意思就是在系统的data目录下方创建了几个xml类型的文件

现在介绍下这些文件

packages.xml保存了系统所有package信息,另外那个packages-backup.xml则是原始文件的一个备份,主要是为了防止源文件的数据丢失,比如手机突然断电,司机等现象

我们来看下载pms构造方法中addSharedUserLPw方法具体是怎么实现的:

SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags) {  
    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;  
    }  
    s = new SharedUserSetting(name, pkgFlags);  
    s.userId = uid;  
    if (addUserIdLPw(uid, s, name)) {  
        mSharedUsers.put(name, s);  
        return s;  
    }  
    return null;  
}  
  
private boolean addUserIdLPw(int uid, Object obj, Object name) {  
    if (uid > Process.LAST_APPLICATION_UID) {  
        return false;  
    }  
  
    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;  
}

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