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;
}