一.scanPackageLI
PKMS 中调用scanDirLI来分析APK 文件,如果目录下的是apk文件或者是目录,会继续调用scanPackageLI函数:
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
... ...
parseFlags |= mDefParseFlags;
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
}
final PackageParser.Package pkg;
try {
pkg = pp.parsePackage(scanFile, parseFlags);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
... ...
}
这段代码主要作用是调用了PackageParser的parsePackage来解析文件,返回Package;
二.PackageParser
PackageParser.parserPackage
public Package parsePackage(File packageFile, int flags) throws PackageParserException {
if (packageFile.isDirectory()) {
// 目录
return parseClusterPackage(packageFile, flags);
} else {
//单个APK
return parseMonolithicPackage(packageFile, flags);
}
}
parseClusterPackage
private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
final PackageLite lite = parseClusterPackageLite(packageDir, 0);//获取应用目录的PackageLite对象,这个对象分开保存了目录下的核心应用以及非核心应用的名称
if (mOnlyCoreApps && !lite.coreApp) {//如果lite中没有核心应用,退出
throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
"Not a coreApp: " + packageDir);
}
final AssetManager assets = new AssetManager();
try {
// Load the base and all splits into the AssetManager
// so that resources can be overriden when parsing the manifests.
loadApkIntoAssetManager(assets, lite.baseCodePath, flags);//装载核心应用的资源
if (!ArrayUtils.isEmpty(lite.splitCodePaths)) {
for (String path : lite.splitCodePaths) {
loadApkIntoAssetManager(assets, path, flags);//再装载非核心应用的资源
}
}
final File baseApk = new File(lite.baseCodePath);
final Package pkg = parseBaseApk(baseApk, assets, flags);//对核心应用解析
... ...
if (!ArrayUtils.isEmpty(lite.splitNames)) {
final int num = lite.splitNames.length;
pkg.splitNames = lite.splitNames;
pkg.splitCodePaths = lite.splitCodePaths;
pkg.splitRevisionCodes = lite.splitRevisionCodes;
pkg.splitFlags = new int[num];
for (int i = 0; i < num; i++) {
parseSplitApk(pkg, i, assets, flags);//对非核心应用的处理
}
}
pkg.codePath = packageDir.getAbsolutePath();
return pkg;
} finally {
IoUtils.closeQuietly(assets);
}
}
parseClusterPackage的主要内容,就是用于解析存在多个APK的文件的Package:
- 1. 调用parseClusterPackageLite解析目录下的多APK文件,获取对应的PackageLite对象lite;
- 2. 创建AssetManager对象,并调用loadApkIntoAssetManager方法载入"base APK"
- 3. 调用parseBaseApk方法获取对应的Package对象
- 4. 遍历所有"拆分APK",然后载入第二步创建的AssetManager对象,这样就实现了资源文件的载入
parseMonolithicPackage
public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
//如果是核心应用则以更轻量级的方式进行解析后,判断是否是核心应用,非核心应用不执行解析过程
if (mOnlyCoreApps) {
final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
if (!lite.coreApp) {
throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
"Not a coreApp: " + apkFile);
}
}
final AssetManager assets = new AssetManager();
try {
//调用parseBaseAPK()继续解析操作
final Package pkg = parseBaseApk(apkFile, assets, flags);
pkg.codePath = apkFile.getAbsolutePath();
return pkg;
} finally {
IoUtils.closeQuietly(assets);
}
}
解析操作继续由parseBaseApk(apkFile, assets, flags)
完成,parseBaseApk(apkFile, assets, flags)最终调用同名函数:
parseBaseApk(Resources res, XmlResourceParser parser, int flags,String[] outError)
private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
String[] outError) throws XmlPullParserException, IOException {
//....省略多行代码....
//循环解析AndroidManifest.xml中的元素
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (tagName.equals("application")) {
//....省略多行代码,重点关注其中调用的parseBaseApplication()方法
}else if (tagName.equals("overlay")) {
//....省略多行代码....
}else if (tagName.equals("key-sets")){
//paseKeySets()
}else if (tagName.equals("permission-group")) {
parsePermissionGroup(pkg, flags, res, parser, attrs,
}else if (tagName.equals("permission")) {
//parsePermission
}else if (tagName.equals("uses-configuration")) {
//....省略多行代码....
}else if (tagName.equals("uses-feature")) {
//parseUsesFeature()
}else if (tagName.equals("feature-group")) {
//....省略多行代码....
}else if (tagName.equals("uses-sdk")) {
//....省略多行代码....
}else if (tagName.equals("supports-screens")) {
//....省略多行代码....
}else if (tagName.equals("protected-broadcast")) {
//....省略多行代码....
}else if (tagName.equals("instrumentation")) {
//....省略多行代码....
}else if (tagName.equals("original-package")) {
//....省略多行代码....
}else if (tagName.equals("adopt-permissions")) {
//....省略多行代码....
}
//....省略多行代码....
}
//....省略多汗代码....
}
此函数就是解析APK 的AndroidManifest.xml 文件;
所以,PackageParser.parsePackage() 函数的作用可以简单的看成完成了 dir 下对应APK 的AndroidManifest.xml 的解析,保存在package 对象中并返回;
- scanPackageLI(File scanFile,...)该函数负责完成APK的扫描工作,APK的扫描工作具体有PackageParser.parsePackage(*)完成。在扫描过程中,会解析AndroidManifiest.xml文件等信息,并将扫描结果存放在PackageParser.Package对象中。
- 在完成包的信息解析之后需要完成包信息同步工作,主要因为:scanPackageLI扫描到的APK可能是已经更名的包、disable的包、需要升级的包、已经安装并且签名冲突的包、被非系统级包替代系统包的情况,需要对这些情况一一处理,保证信息的正确性。
- 如果Package需要Rename或者Update则会进行签名比较,以防止签名不一致的情况;
- 最终会调用scanPackageLI(PackageParser.Package,....)函数完成实际的Package安装或更新操作。
- 在扫描过程中,Package的Rename、Update、Install操作都是由scanPackage(PackageParser,int,int,long,UserHandler)来完成.该函数会调用scanPackageDirtyLI(...)完成具体的操作
scanPackageDirtyLI
需要注意的是:不论是开机扫描安装APK,还是通过adb命令安装APK,最终都会调用scanPackageDirtyLI函数进行APK安装
总结一下:
1 .任一时刻,系统中安装过的apk都会被解析完成,包信息被存放在PackageManagerService中的mPackages,它是以包名为Key,以PackageParser.Package为Value的HashMap。
2 .PMS中scanPackageLI()开机扫描已安装的apk,installPackageLI()安装新apk,最终都会走到PackageParser.parseBaseApplication()解析应用manifest文件,在scanPackageDirtyLI()中添加到mPackages.其它地方获取ApplicationInfo实例,都会间接地调用到PackageParser.generateApplicationInfo().