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!