前面学到PMS构造函数中调用scanDirTraceLI()方法扫描系统app/priv-app/framework等目录下的apk文件,然后调用通过ParallelPackageParser提交(submit())apk给PackageParser解析,PackageParser调用parserPackage()方法解析每一个apk,并将四大组件和其他相关等信息解析出来放入package对象中,然后将所有的package对象放入集合mPackages中。然后PMS的包扫描和解析过程基本上就算是完成了。但扫描和解析完成之后,关于apk的信息都存储在队列中,我们还需要将它们从队列中取出来,同步到PMS的属性中,然后将这些apk的信息在packages.xml和packages.list文件中更新。
这里我们来学习扫描和解析完成之后,apk数据的同步和配置更新。
在使用线程池执行所有的apk解析后,所有的解析结果都保存在队列中,系统会循环调用take()方法取出解析的结果。
for (; fileCount > 0; fileCount--) {
ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags,
currentTime, null);
}
1 scanPackageChildLI() 获取扫描到的ParseResult中的Pakcage对象
取出apk文件解析结果后,调用scanPackageChildLI()扫描获取到的ParseResult中的Pakcage对象,scanPackageChildLI()中直接调用addForInitLI()方法.
//addForInitLI()
synchronized (mPackages) {
final PackageSetting installedPkgSetting = mSettings.getPackageLPr(pkg.packageName); // 1、获取从配置文件中读取的Settings
final PackageParser.Package scannedPkg = scanPackageNewLI(pkg, parseFlags, scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user); // 调用scanPackageNewLI将pkg中的数据保存到PMS的变量中
}
// scanPackageNewLI():创建ScanRequest对象,执行文件扫描修改或更新对应的PackageSetting对象
final ScanRequest request = new ScanRequest(pkg, sharedUserSetting,
pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting,
originalPkgSetting, realPkgName, parseFlags, scanFlags,
(pkg == mPlatformPackage), user);
final ScanResult result = scanPackageOnlyLI(request, mFactoryTest, currentTime);
if (result.success) {
commitScanResultsLocked(request, result); // 调用commitScanResultsLocked()
}
commitScanResultsLocked()中直接调用commitPackageSettings()处理apk的解析数据 。
commitPackageSettings(pkg, oldPkg, pkgSetting, user, scanFlags,
(parseFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/); // 提交包解析数据
2 commitPackageSettings()将package信息保存到PMS内部变量中
commitPackageSettings()方法主要是将解析得到的Package中的信息保存到PMS内部变量中,并创建程序包所需的各种文件信息。
private void commitPackageSettings(PackageParser.Package pkg,
@Nullable PackageParser.Package oldPkg, PackageSetting pkgSetting, UserHandle user,
final @ScanFlags int scanFlags, boolean chatty) {
final String pkgName = pkg.packageName;
if (pkg.packageName.equals("android")) { // 1、针对系统包,特殊处理属性的初始化
mPlatformPackage = pkg;
pkg.mVersionCode = mSdkVersion;
mAndroidApplication = pkg.applicationInfo;
mResolveActivity.applicationInfo = mAndroidApplication;
mResolveActivity.name = ResolverActivity.class.getName();
......
mResolveComponentName = new ComponentName(
mAndroidApplication.packageName, mResolveActivity.name);
}
int N = pkg.usesLibraries != null ? pkg.usesLibraries.size() : 0;
for (int i=0; i<N; i++) {
String file = mSharedLibraries.get(pkg.usesLibraries.get(i));
mTmpSharedLibraries[num] = file; // 遍历所有的user-library标签保存在数组中
num++;
}
if (!verifySignaturesLP(pkgSetting, pkg)) { // 校验签名文件
…….
}
int N = pkg.providers.size();
StringBuilder r = null;
int i;
for (i=0; i<N; i++) {
PackageParser.Provider p = pkg.providers.get(i); //遍历提取每个provider
p.info.processName = fixProcessName(pkg.applicationInfo.processName,
p.info.processName, pkg.applicationInfo.uid);
mProvidersByComponent.put(new ComponentName(p.info.packageName,
p.info.name), p); // 针对Provider创建ComponentName对象,保存在mProvidersByComponent集合中
if (p.info.authority != null) {
String names[] = p.info.authority.split(";"); // 获取Provider的权限信息
p.info.authority = null;
for (int j = 0; j < names.length; j++) {
if (j == 1 && p.syncable) {
p = new PackageParser.Provider(p);
p.syncable = false;
}
if (!mProviders.containsKey(names[j])) {
mProviders.put(names[j], p); // 将权限和对应的Provider以键值对保存在 mProviders 集合中
}
}
}
}
N = pkg.services.size();
r = null;
for (i=0; i<N; i++) {
PackageParser.Service s = pkg.services.get(i);
s.info.processName = fixProcessName(pkg.applicationInfo.processName,
s.info.processName, pkg.applicationInfo.uid);
mServices.addService(s);
N = pkg.receivers.size();
r = null;
for (i=0; i<N; i++) {
PackageParser.Activity a = pkg.receivers.get(i);
a.info.processName = fixProcessName(pkg.applicationInfo.processName,
a.info.processName, pkg.applicationInfo.uid);
mReceivers.addActivity(a, "receiver");
}
N = pkg.activities.size();
r = null;
for (i=0; i<N; i++) {
PackageParser.Activity a = pkg.activities.get(i);
a.info.processName = fixProcessName(pkg.applicationInfo.processName,
a.info.processName, pkg.applicationInfo.uid);
mActivities.addActivity(a, "activity");
}
在commitPackageSettings中,主要是将每个apk文件获得的Package对象中保存的四大组件信息分别提取保存在PMS内部对应的属性中,在PMS内部有4个专门储存四大组件的属性:
final ActivityIntentResolver mActivities = new ActivityIntentResolver();
final ActivityIntentResolver mReceivers = new ActivityIntentResolver();
final ServiceIntentResolver mServices = new ServiceIntentResolver();
final ProviderIntentResolver mProviders = new ProviderIntentResolver();
1.ActivityIntentResolver.addActivity():处理Activity和Receiver分别保存在各自的ArrayMap中
public final void addActivity(PackageParser.Activity a, String type) {
mActivities.put(a.getComponentName(), a); // 1、获取内部的Component对象,在Activity会自动创建Component对象
final int NI = a.intents.size();
for (int j=0; j<NI; j++) {
PackageParser.ActivityIntentInfo intent = a.intents.get(j); // 获取Activity中设置的intent
addFilter(intent); // 添加Intent过滤
}
}
2.ServiceIntentResolver.addActivity():将Package中极细获取的Service对象,保存在ArrayMap中
public final void addService(PackageParser.Service s) {
mServices.put(s.getComponentName(), s); //保存service
final int NI = s.intents.size();
int j;
for (j=0; j<NI; j++) {
PackageParser.ServiceIntentInfo intent = s.intents.get(j);
addFilter(intent);
}
}
3.ProviderIntentResolver.addActivity():将Package中极细获取的Provider对象,保存在ArrayMap中。
public final void addProvider(PackageParser.Provider p) {
if (mProviders.containsKey(p.getComponentName())) {
return;
}
mProviders.put(p.getComponentName(), p); // 保存provider
final int NI = p.intents.size();
int j;
for (j = 0; j < NI; j++) {
PackageParser.ProviderIntentInfo intent = p.intents.get(j);
addFilter(intent); // 添加查找过滤的intent
}
}
3 updateAllSharedLibrariesLPw同步共享Library
接着是调用updateAllSharedLibrariesLPw更新所有package的usesLibraryFiles数据,为什么要做更新?因为package在AndroidManifest里头使用use-library描述要引用的library,在系统mSharedLibraries里可能是未定义的,所以,需要做数据同步。app可以在Manifest里头声明自身运行需要额外的library,但是,这里仅仅只是声明,最终还是要看系统有没有配置这个shareLibrary,系统配置的shareLibrary可在初始化SystemConfig时知道,如果app的uses-library在系统中不存在,apk会安装失败。
private ArrayList<PackageParser.Package> updateAllSharedLibrariesLPw(
PackageParser.Package changingPkg) {
ArrayList<PackageParser.Package> res = null;
for (PackageParser.Package pkg : mPackages.values()) {
if (changingPkg != null
&& !hasString(pkg.usesLibraries, changingPkg.libraryNames)
&& !hasString(pkg.usesOptionalLibraries, changingPkg.libraryNames)
&& !ArrayUtils.contains(pkg.usesStaticLibraries,
changingPkg.staticSharedLibName)) {
return null;
}
if (res == null) {
res = new ArrayList<>();
}
res.add(pkg);
try {
updateSharedLibrariesLPr(pkg, changingPkg);
} catch (PackageManagerException e) {
// If a system app update or an app and a required lib missing we
// delete the package and for updated system apps keep the data as
// it is better for the user to reinstall than to be in an limbo
// state. Also libs disappearing under an app should never happen
// - just in case.
if (!pkg.isSystem() || pkg.isUpdatedSystemApp()) {
final int flags = pkg.isUpdatedSystemApp()
? PackageManager.DELETE_KEEP_DATA : 0;
deletePackageLIF(pkg.packageName, null, true, sUserManager.getUserIds(),
flags , null, true, null);
}
Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
}
}
return res;
}
4 updateAllPermissions权限处理
调用updateAllPermissions更新系统permission trees和permission 列表
mPermissionManager.updateAllPermissions(
StorageManager.UUID_PRIVATE_INTERNAL, sdkUpdated, mPackages.values(),
mPermissionCallback);
ver.sdkVersion = mSdkVersion;
在PMS构造时,会调用SystemConfig.getPermissions()获取系统builtin权限数据
// Propagate permission configuration in to package manager.
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.gids = appendInts(bp.gids, perm.gids);
}
}
遍历systemConfig定义的permission时,接着判断mSettings.mPermissions是否已经存在该权限的定义,如果不存在,新建一个BasePermission,权限source package为android,type为builtin,接着更新权限对应的supplementary gids;
扫描apk时权限数据的初始化:
//PackageParser.parsePermission
private Permission parsePermission(Package owner, Resources res,
XmlPullParser parser, AttributeSet attrs, String[] outError)
throws XmlPullParserException, IOException {
Permission perm = new Permission(owner);
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifestPermission);
if (!parsePackageItemInfo(owner, perm.info, outError,
"<permission>", sa,
com.android.internal.R.styleable.AndroidManifestPermission_name,
com.android.internal.R.styleable.AndroidManifestPermission_label
com.android.internal.R.styleable.AndroidManifestPermission_icon,
com.android.internal.R.styleable.AndroidManifestPermission_logo,
com.android.internal.R.styleable.AndroidManifestPermission_banner)) {
sa.recycle();
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return null;
}
...
owner.permissions.add(perm);
return perm;
}
permission和permission tree都保存到Package.permissions列表中,通过字段perm.tree是true还是false来区分是否是permissiontree
在app扫描结束后,permission数据已经被全部拿到,但是现在数据都还只是保存在Package内部,所以还需要将permission数据添加到PMS permission Map。
对大部分app来说,如果要使用某权限,必须要在manifest进行声明, 比如:
<uses-permissionandroid:name="android.permission.INTERNET" />
然后PackageParser. parseBaseApk时,会调用parseUsesPermission对声明解析使用的权限数据。
5 mSettings.writeLPr()配置更新
mSettings.writeLPr():将mPackages中的数据分别写入package.xml和package.list文件中
void writeLPr() {
if (mSettingsFilename.exists()) {
if (!mBackupSettingsFilename.exists()) { // 重命名文件
if (!mSettingsFilename.renameTo(mBackupSettingsFilename)) {
Slog.wtf(PackageManagerService.TAG,
"Unable to backup package manager settings, "
+ " current changes will be lost at reboot");
return;
}
} else {
mSettingsFilename.delete(); //删除package文件
}
}
FileOutputStream fstr = new FileOutputStream(mSettingsFilename);
BufferedOutputStream str = new BufferedOutputStream(fstr);
......
for (final PackageSetting pkg : mPackages.values()) {
writePackageLPr(serializer, pkg); // 写入配置信息
}
......
}
writePackageListLPr(); // 更新package.list文件
主要是以下几件事:
1.先判断packages.xml和backup.xml文件是否存在,如果两个都存在则删除packages.xml
2.如果backup.xml文件不存在,则将packages.xml重命名为backup.xml
3.创建新的packages.xml文件,并将mSetting中的内容写入文件夹
4.删除backup文件,并重新生成packages.list文件
至此apk的扫描和解析的数据同步以及配置更新就完成了,关于权限的处理,Android源码的更新比较快,我上述写的方法是Android9的源码中的逻辑,在Android的早些版本的源码中调用的是updatePermissionsLPw这个方法循环遍历mSettings.mPackages集合来将所有的应用赋予权限,而最后的writeLPr方法则是将一些应用信息保存到packages.xml文件中。
参考链接:https://blog.csdn.net/Alexwll/article/details/102777742