它实现在ParsingPackageUtils类的静态方法parseDefault(ParseInput input, File file, @ParseFlags int parseFlags, @NonNull List
@NonNull
public static ParseResult<ParsingPackage> parseDefault(ParseInput input, File file,
@ParseFlags int parseFlags,
@NonNull List<PermissionManager.SplitPermissionInfo> splitPermissions,
boolean collectCertificates) {
ParseResult<ParsingPackage> result;
ParsingPackageUtils parser = new ParsingPackageUtils(false, null, null, splitPermissions,
new Callback() {
@Override
public boolean hasFeature(String feature) {
// Assume the device doesn't support anything. This will affect permission
// parsing and will force declarations to include all
// requiredNotFeature permissions and exclude all requiredFeature
// permissions. This mirrors the old behavior.
return false;
}
@Override
public ParsingPackage startParsingPackage(
@NonNull String packageName,
@NonNull String baseApkPath,
@NonNull String path,
@NonNull TypedArray manifestArray, boolean isCoreApp) {
return new ParsingPackageImpl(packageName, baseApkPath, path,
manifestArray);
}
});
try {
result = parser.parsePackage(input, file, parseFlags);
if (result.isError()) {
return result;
}
} catch (PackageParser.PackageParserException e) {
return input.error(PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Error parsing package", e);
}
try {
ParsingPackage pkg = result.getResult();
if (collectCertificates) {
pkg.setSigningDetails(
ParsingPackageUtils.getSigningDetails(pkg, false /* skipVerify */));
}
// Need to call this to finish the parsing stage
pkg.hideAsParsed();
return input.success(pkg);
} catch (PackageParser.PackageParserException e) {
return input.error(PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Error collecting package certificates", e);
}
}
1、新建 ParsingPackageUtils 实例 在这里设置的回调Callback的startParsingPackage() 方法,它是用来生成parseDefault()实际返回的对象类型。
2、调用新生成的ParsingPackageUtils 实例的parsePackage()得到ParseResult类型result。
3、根据参数 collectCertificates 来判断是否执行签名验证。可以参考Android APK文件的签名V2查找、验证,Android APK文件完整性验证
其中比较主要的是第二步,解析包得到包信息。
相关代码如下:
public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile,
int flags)
throws PackageParserException {
if (packageFile.isDirectory()) {
return parseClusterPackage(input, packageFile, flags);
} else {
return parseMonolithicPackage(input, packageFile, flags);
}
}
根据参数packageFile 是目录还是文件分别执行 parseClusterPackage(input, packageFile, flags) 还是 parseMonolithicPackage(input, packageFile, flags)。
像用户手动安装应用的时候,就是文件形式的。在开机时安装应用,则是目录的形式。
private ParseResult<ParsingPackage> parseMonolithicPackage(ParseInput input, File apkFile,
int flags) throws PackageParserException {
final ParseResult<PackageLite> liteResult =
ApkLiteParseUtils.parseMonolithicPackageLite(input, apkFile, flags);
if (liteResult.isError()) {
return input.error(liteResult);
}
final PackageLite lite = liteResult.getResult();
if (mOnlyCoreApps && !lite.isCoreApp()) {
return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED,
"Not a coreApp: " + apkFile);
}
final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
try {
final ParseResult<ParsingPackage> result = parseBaseApk(input,
apkFile,
apkFile.getCanonicalPath(),
assetLoader, flags);
if (result.isError()) {
return input.error(result);
}
return input.success(result.getResult()
.setUse32BitAbi(lite.isUse32bitAbi()));
} catch (IOException e) {
return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to get path: " + apkFile, e);
} finally {
IoUtils.closeQuietly(assetLoader);
}
}
首先通过ApkLiteParseUtils.parseMonolithicPackageLite(input, apkFile, flags)得到ParseResult类型liteResult。
其次生成一个DefaultSplitAssetLoader类对象。
通过parseBaseApk()得到ParseResult类对象result。
这里提到的lite.isUse32bitAbi(),该值是Manifest配置文件中标签 application 下的 use32bitAbi 属性值,如果不配置 默认为false。
它实现在ApkLiteParseUtils类的parseMonolithicPackageLite()方法中:
/**
* Parse lightweight details about a single APK files.
*/
public static ParseResult<PackageLite> parseMonolithicPackageLite(ParseInput input,
File packageFile, int flags) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
try {
final ParseResult<ApkLite> result = parseApkLite(input, packageFile, flags);
if (result.isError()) {
return input.error(result);
}
final ApkLite baseApk = result.getResult();
final String packagePath = packageFile.getAbsolutePath();
return input.success(
new PackageLite(packagePath, baseApk.getPath(), baseApk, null,
null, null, null, null, null, baseApk.getTargetSdkVersion()));
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
可见这里主要是调用parseApkLite(input, packageFile, flags)得到ApkLite对象,然后将它封装到PackageLite对象中,并且返回。其中,PackageLite的构造函数中,使用了packagePath和baseApk.getPath()。packagePath是文件的绝对路径。baseApk.getPath()是什么呢,在这里也是文件的绝对路径。这俩值是赋值给了PackageLite的成员变量mPath和mBaseApkPath。看其注释,说它俩可能是不同的,因为移动或者重命名APK文件。
parseApkLite(input, packageFile, flags)主要接着调用parseApkLiteInner(ParseInput input, File apkFile, FileDescriptor fd, String debugPathName, int flags),它再调用parseApkLite(ParseInput input, String codePath, XmlResourceParser parser, PackageParser.SigningDetails signingDetails),主要解析的就是"AndroidManifest.xml"文件,但是它不会解析四大组件相关的属性信息。所以说它是轻量级。主要的解析信息都在parseApkLite(ParseInput input, String codePath, XmlResourceParser parser, PackageParser.SigningDetails signingDetails)中,看一下最后生成的ApkLite对象:
return input.success(
new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit,
configForSplit, usesSplitName, isSplitRequired, versionCode,
versionCodeMajor, revisionCode, installLocation, verifiers, signingDetails,
coreApp, debuggable, profilableByShell, multiArch, use32bitAbi,
useEmbeddedDex, extractNativeLibs, isolatedSplits, targetPackage,
overlayIsStatic, overlayPriority, minSdkVersion, targetSdkVersion,
rollbackDataPolicy));
这里面的值都是从"AndroidManifest.xml"文件中取得的,后面用到再说。
它主要实现在parseBaseApk(ParseInput input, File apkFile, String codePath, SplitAssetLoader assetLoader, int flags),
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
String codePath, SplitAssetLoader assetLoader, int flags)
throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
String volumeUuid = null;
if (apkPath.startsWith(MNT_EXPAND)) {
final int end = apkPath.indexOf('/', MNT_EXPAND.length());
volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
}
if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
final AssetManager assets = assetLoader.getBaseAssetManager();
final int cookie = assets.findCookieForPath(apkPath);
if (cookie == 0) {
return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST,
"Failed adding asset path: " + apkPath);
}
try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,
ANDROID_MANIFEST_FILENAME)) {
final Resources res = new Resources(assets, mDisplayMetrics, null);
ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,
parser, flags);
if (result.isError()) {
return input.error(result.getErrorCode(),
apkPath + " (at " + parser.getPositionDescription() + "): "
+ result.getErrorMessage());
}
final ParsingPackage pkg = result.getResult();
if (assets.containsAllocatedTable()) {
final ParseResult<?> deferResult = input.deferError(
"Targeting R+ (version " + Build.VERSION_CODES.R + " and above) requires"
+ " the resources.arsc of installed APKs to be stored uncompressed"
+ " and aligned on a 4-byte boundary",
DeferredError.RESOURCES_ARSC_COMPRESSED);
if (deferResult.isError()) {
return input.error(INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED,
deferResult.getErrorMessage());
}
}
ApkAssets apkAssets = assetLoader.getBaseApkAssets();
boolean definesOverlayable = false;
try {
definesOverlayable = apkAssets.definesOverlayable();
} catch (IOException ignored) {
// Will fail if there's no packages in the ApkAssets, which can be treated as false
}
if (definesOverlayable) {
SparseArray<String> packageNames = assets.getAssignedPackageIdentifiers();
int size = packageNames.size();
for (int index = 0; index < size; index++) {
String packageName = packageNames.valueAt(index);
Map<String, String> overlayableToActor = assets.getOverlayableMap(packageName);
if (overlayableToActor != null && !overlayableToActor.isEmpty()) {
for (String overlayable : overlayableToActor.keySet()) {
pkg.addOverlayable(overlayable, overlayableToActor.get(overlayable));
}
}
}
}
pkg.setVolumeUuid(volumeUuid);
if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
pkg.setSigningDetails(getSigningDetails(pkg, false));
} else {
pkg.setSigningDetails(SigningDetails.UNKNOWN);
}
return input.success(pkg);
} catch (Exception e) {
return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to read manifest from " + apkPath, e);
}
}
首先得到解析包的volumeUuid,当然这得是它的安装路径是以"/mnt/expand/“开头。然后通过截取”/mnt/expand/“和它的下一个”/“之间的值作为volumeUuid。
assetLoader在这里是DefaultSplitAssetLoader对象,它是可以用来加载splits APK的,所以它可能对应有多个APK文件。这里通过文件路径apkPath找到AssetManager中对应的APK的位置。然后再通过cookie找到对应APK文件的"AndroidManifest.xml”,最后它的解析信息在XmlResourceParser类型的parser对象中。
其实解析APK文件也是挺复杂的,它的内容在AssetManager的getBaseAssetManager()中。它涉及到C++层的实现。这里只是简单描述一下相应过程,说通逻辑。
接着就是调用另一重载函数parseBaseApk(),来生成ParsingPackage对象。看一下它的实现:
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
String codePath, Resources res, XmlResourceParser parser, int flags)
throws XmlPullParserException, IOException {
final String splitName;
final String pkgName;
ParseResult<Pair<String, String>> packageSplitResult =
ApkLiteParseUtils.parsePackageSplitNames(input, parser);
if (packageSplitResult.isError()) {
return input.error(packageSplitResult);
}
Pair<String, String> packageSplit = packageSplitResult.getResult();
pkgName = packageSplit.first;
splitName = packageSplit.second;
if (!TextUtils.isEmpty(splitName)) {
return input.error(
PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
"Expected base APK, but found split " + splitName
);
}
final TypedArray manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest);
try {
final boolean isCoreApp =
parser.getAttributeBooleanValue(null, "coreApp", false);
final ParsingPackage pkg = mCallback.startParsingPackage(
pkgName, apkPath, codePath, manifestArray, isCoreApp);
final ParseResult<ParsingPackage> result =
parseBaseApkTags(input, pkg, manifestArray, res, parser, flags);
if (result.isError()) {
return result;
}
return input.success(pkg);
} finally {
manifestArray.recycle();
}
}
ApkLiteParseUtils.parsePackageSplitNames(input, parser)是为了解析"package"、"split"属性,解析完之后,将对应值放在Pair里。
接下里会调用回调mCallback.startParsingPackage()方法,我们返回到ParsingPackageUtils的定义处。可知,它的实际类型是ParsingPackageImpl对象。
接着调用parseBaseApkTags(input, pkg, manifestArray, res, parser, flags)来得到具体的解析包对象。
private ParseResult<ParsingPackage> parseBaseApkTags(ParseInput input, ParsingPackage pkg,
TypedArray sa, Resources res, XmlResourceParser parser, int flags)
throws XmlPullParserException, IOException {
ParseResult<ParsingPackage> sharedUserResult = parseSharedUser(input, pkg, sa);
if (sharedUserResult.isError()) {
return sharedUserResult;
}
pkg.setInstallLocation(anInteger(PARSE_DEFAULT_INSTALL_LOCATION,
R.styleable.AndroidManifest_installLocation, sa))
.setTargetSandboxVersion(anInteger(PARSE_DEFAULT_TARGET_SANDBOX,
R.styleable.AndroidManifest_targetSandboxVersion, sa))
/* Set the global "on SD card" flag */
.setExternalStorage((flags & PARSE_EXTERNAL_STORAGE) != 0);
boolean foundApp = false;
final int depth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
|| parser.getDepth() > depth)) {
if (type != XmlPullParser.START_TAG) {
continue;
}
String tagName = parser.getName();
final ParseResult result;
// has special logic, so it's handled outside the general method
if (TAG_APPLICATION.equals(tagName)) {
if (foundApp) {
if (RIGID_PARSER) {
result = input.error(" has more than one " );
} else {
Slog.w(TAG, " has more than one " );
result = input.success(null);
}
} else {
foundApp = true;
result = parseBaseApplication(input, pkg, res, parser, flags);
}
} else {
result = parseBaseApkTag(tagName, input, pkg, res, parser, flags);
}
if (result.isError()) {
return input.error(result);
}
}
if (!foundApp && ArrayUtils.size(pkg.getInstrumentations()) == 0) {
ParseResult<?> deferResult = input.deferError(
" does not contain an or " ,
DeferredError.MISSING_APP_TAG);
if (deferResult.isError()) {
return input.error(deferResult);
}
}
…………
return input.success(pkg);
}
可以看到这里主要是manifest文件中"application"标签和同级其他标签下的属性和标签。"application"标签下的主要是调用parseBaseApplication(input, pkg, res, parser, flags),和"application"标签同级的使用parseBaseApkTag(tagName, input, pkg, res, parser, flags)解析。
在这里parseBaseApplication(input, pkg, res, parser, flags)就会将四大组件的信息都解析出来。
这样执行完毕,就将解析包信息都放在ParsingPackageImpl对象中。
所谓以目录形式解析,就是给了一个文件是目录,安装文件包括在它包括的文件中。
看下它的实现:
private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir,
int flags) {
final ParseResult<PackageLite> liteResult =
ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, 0);
if (liteResult.isError()) {
return input.error(liteResult);
}
final PackageLite lite = liteResult.getResult();
if (mOnlyCoreApps && !lite.isCoreApp()) {
return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED,
"Not a coreApp: " + packageDir);
}
// Build the split dependency tree.
SparseArray<int[]> splitDependencies = null;
final SplitAssetLoader assetLoader;
if (lite.isIsolatedSplits() && !ArrayUtils.isEmpty(lite.getSplitNames())) {
try {
splitDependencies = SplitAssetDependencyLoader.createDependenciesFromPackage(lite);
assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags);
} catch (SplitAssetDependencyLoader.IllegalDependencyException e) {
return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage());
}
} else {
assetLoader = new DefaultSplitAssetLoader(lite, flags);
}
try {
final File baseApk = new File(lite.getBaseApkPath());
final ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk,
lite.getPath(), assetLoader, flags);
if (result.isError()) {
return input.error(result);
}
ParsingPackage pkg = result.getResult();
if (!ArrayUtils.isEmpty(lite.getSplitNames())) {
pkg.asSplit(
lite.getSplitNames(),
lite.getSplitApkPaths(),
lite.getSplitRevisionCodes(),
splitDependencies
);
final int num = lite.getSplitNames().length;
for (int i = 0; i < num; i++) {
final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
parseSplitApk(input, pkg, i, splitAssets, flags);
}
}
pkg.setUse32BitAbi(lite.isUse32bitAbi());
return input.success(pkg);
} catch (PackageParserException e) {
return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to load assets: " + lite.getBaseApkPath(), e);
} finally {
IoUtils.closeQuietly(assetLoader);
}
}
先通过ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, 0)得到PackageLite对象。
接着创建SplitAssetLoader对象。lite.isIsolatedSplits()来自基础APK的配置文件里的"isolatedSplits"属性值,默认为false。如果它设置为true,并且存在splite apk,则会构造SplitAssetDependencyLoader。它会构造split apk间的依赖关系,如果存在依赖,会在加载apk(这里主要是加载ID资源表)的时候,一起加载。
再通过parseBaseApk(input, baseApk, lite.getPath(), assetLoader, flags)得到ParsingPackage对象。
如果是split apk,会接着调用parseSplitApk(input, pkg, i, splitAssets, flags)。
看下ApkLiteParseUtils类的parseClusterPackageLite()方法:
/**
* Parse lightweight details about a directory of APKs.
*/
public static ParseResult<PackageLite> parseClusterPackageLite(ParseInput input,
File packageDir, int flags) {
final File[] files = packageDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
return input.error(PackageManager.INSTALL_PARSE_FAILED_NOT_APK,
"No packages found in split");
}
// Apk directory is directly nested under the current directory
if (files.length == 1 && files[0].isDirectory()) {
return parseClusterPackageLite(input, files[0], flags);
}
String packageName = null;
int versionCode = 0;
final ArrayMap<String, ApkLite> apks = new ArrayMap<>();
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
try {
for (File file : files) {
if (isApkFile(file)) {
final ParseResult<ApkLite> result = parseApkLite(input, file, flags);
if (result.isError()) {
return input.error(result);
}
final ApkLite lite = result.getResult();
// Assert that all package names and version codes are
// consistent with the first one we encounter.
if (packageName == null) {
packageName = lite.getPackageName();
versionCode = lite.getVersionCode();
} else {
if (!packageName.equals(lite.getPackageName())) {
return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
"Inconsistent package " + lite.getPackageName() + " in " + file
+ "; expected " + packageName);
}
if (versionCode != lite.getVersionCode()) {
return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
"Inconsistent version " + lite.getVersionCode() + " in " + file
+ "; expected " + versionCode);
}
}
// Assert that each split is defined only oncuses-static-libe
if (apks.put(lite.getSplitName(), lite) != null) {
return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
"Split name " + lite.getSplitName()
+ " defined more than once; most recent was " + file);
}
}
}
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
final ApkLite baseApk = apks.remove(null);
return composePackageLiteFromApks(input, packageDir, baseApk, apks);
}
如果当前目录下面只有一个目录,会递归调用parseClusterPackageLite(ParseInput input, File packageDir, int flags)方法,并且会将这个目录作为参数传递。
如果目录下有多个以".apk"结尾的文件,则它为split apk安装形式。首先通过parseApkLite(input, file, flags)解析得到ApkLite对象,这个前面讲过。接下来,可以看到如果是split apk安装形式,基本apk是不用配置"split"属性值,其他apk则是需要配置不同的"split"属性值。并且会将"split"属性值和ApkLite对象放入ArrayMap
接下来会调用composePackageLiteFromApks(input, packageDir, baseApk, apks),最后它会调用composePackageLiteFromApks( ParseInput input, File packageDir, ApkLite baseApk, ArrayMap
public static ParseResult<PackageLite> composePackageLiteFromApks(
ParseInput input, File packageDir, ApkLite baseApk,
ArrayMap<String, ApkLite> splitApks, boolean apkRenamed) {
if (baseApk == null) {
return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
"Missing base APK in " + packageDir);
}
// Always apply deterministic ordering based on splitName
final int size = ArrayUtils.size(splitApks);
String[] splitNames = null;
boolean[] isFeatureSplits = null;
String[] usesSplitNames = null;
String[] configForSplits = null;
String[] splitCodePaths = null;
int[] splitRevisionCodes = null;
if (size > 0) {
splitNames = new String[size];
isFeatureSplits = new boolean[size];
usesSplitNames = new String[size];
configForSplits = new String[size];
splitCodePaths = new String[size];
splitRevisionCodes = new int[size];
splitNames = splitApks.keySet().toArray(splitNames);
Arrays.sort(splitNames, sSplitNameComparator);
for (int i = 0; i < size; i++) {
final ApkLite apk = splitApks.get(splitNames[i]);
usesSplitNames[i] = apk.getUsesSplitName();
isFeatureSplits[i] = apk.isFeatureSplit();
configForSplits[i] = apk.getConfigForSplit();
splitCodePaths[i] = apkRenamed ? new File(packageDir,
splitNameToFileName(apk)).getAbsolutePath() : apk.getPath();
splitRevisionCodes[i] = apk.getRevisionCode();
}
}
final String codePath = packageDir.getAbsolutePath();
final String baseCodePath = apkRenamed ? new File(packageDir,
splitNameToFileName(baseApk)).getAbsolutePath() : baseApk.getPath();
return input.success(
new PackageLite(codePath, baseCodePath, baseApk, splitNames, isFeatureSplits,
usesSplitNames, configForSplits, splitCodePaths, splitRevisionCodes,
baseApk.getTargetSdkVersion()));
}
这里主要是处理split apk的多个文件的情况,这里注意的一点splitCodePath的名字会根据参数apkRenamed 来赋不同的值,如果apkRenamed 为true,则值为目录 + “split_” + splitName + “.apk”;如果为false,则为文件的路径名。
同样在为baseCodePath 赋值时,apkRenamed 为true,则值为目录 + “base.apk”;如果为false,则为文件的路径名。
在这里codePath 和 baseCodePath 的值是不同的,codePath为目录名,baseCodePath 为基本apk文件路径。它俩值分别对应PackageLite对象的成员mPath、mBaseApkPath。
这样就生成了PackageLite对象。
实现在parseBaseApk(ParseInput input, File apkFile, String codePath, SplitAssetLoader assetLoader, int flags)中,该方法在前面说过,在这里不同的是,codePath是目录,不是安装文件。
从前面知道,最终得到的解析包是ParsingPackageImpl对象,它里面包含所有解析出来的信息。看一下它的初始化函数:
@VisibleForTesting
public ParsingPackageImpl(@NonNull String packageName, @NonNull String baseApkPath,
@NonNull String path, @Nullable TypedArray manifestArray) {
this.packageName = TextUtils.safeIntern(packageName);
this.mBaseApkPath = baseApkPath;
this.mPath = path;
if (manifestArray != null) {
versionCode = manifestArray.getInteger(R.styleable.AndroidManifest_versionCode, 0);
versionCodeMajor = manifestArray.getInteger(
R.styleable.AndroidManifest_versionCodeMajor, 0);
setBaseRevisionCode(
manifestArray.getInteger(R.styleable.AndroidManifest_revisionCode, 0));
setVersionName(manifestArray.getNonConfigurationString(
R.styleable.AndroidManifest_versionName, 0));
setCompileSdkVersion(manifestArray.getInteger(
R.styleable.AndroidManifest_compileSdkVersion, 0));
setCompileSdkVersionCodename(manifestArray.getNonConfigurationString(
R.styleable.AndroidManifest_compileSdkVersionCodename, 0));
setIsolatedSplitLoading(manifestArray.getBoolean(
R.styleable.AndroidManifest_isolatedSplits, false));
}
}
在这里,我们知道mBaseApkPath 和mPath 的区别了,在用目录形式的解析时,mPath 是包含apk文件的目录。它里面包含特别多的成员变量和方法。在这里,我们知道它是从以上哪些函数中得到的,等以后使用到,就去这些函数中查找。
解析apk包信息时,一种是通过apk文件作为参数解析,另外一种是通过apk文件所在目录作为参数来解析。
解析出来的类对象是ParsingPackageImpl类型的,它主要解析的是"AndroidManifest.xml"文件,类对象的成员也主要对应配置文件的属性和值。