1. PackageParser.parseBaseApk中,定义变量Resources res, XmlResourceParser parser
private Package parseBaseApk(File apkFile, AssetManager assets, 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);
}
mParseError = PackageManager.INSTALL_SUCCEEDED;
mArchiveSourcePath = apkFile.getAbsolutePath();
if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
final int cookie = loadApkIntoAssetManager(assets, apkPath, flags); //将apkPath如/system/priv-app/Dialer/Dialer.apk加载进assets资源管理器
Resources res = null;
XmlResourceParser parser = null; //变量申名
2. 变量附值, 1中loadApkIntoAssetManager己将数据加载进AssetManager assets
try {
res = new Resources(assets, mMetrics, null); //创建Resources类
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); //资源管理器打开资料中的AndroidManifest.xml数据给解析器parser
final String[] outError = new String[1];
final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
if (pkg == null) {
throw new PackageParserException(mParseError,
apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
}
pkg.setVolumeUuid(volumeUuid);
pkg.setApplicationVolumeUuid(volumeUuid);
pkg.setBaseCodePath(apkPath);
pkg.setSignatures(null);
return pkg;
} catch (PackageParserException e) {
throw e;
} catch (Exception e) {
throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to read manifest from " + apkPath, e);
} finally {
IoUtils.closeQuietly(parser);
}
assets parseMonolithicPackage中定义:
public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
final AssetManager assets = newConfiguredAssetManager();
final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
if (mOnlyCoreApps) {
if (!lite.coreApp) {
throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
"Not a coreApp: " + apkFile);
}
}
try {
final Package pkg = parseBaseApk(apkFile, assets, flags);
pkg.setCodePath(apkFile.getAbsolutePath());
pkg.setUse32bitAbi(lite.use32bitAbi);
return pkg;
} finally {
IoUtils.closeQuietly(assets);
}
}
assets创建:
private static AssetManager newConfiguredAssetManager() {
AssetManager assetManager = new AssetManager();
assetManager.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Build.VERSION.RESOURCES_SDK_INT);
return assetManager;
}
3. 进一步通过parseBaseApk解析,res获取AndroidManifest.xml中属性信息
private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags,
String[] outError) throws XmlPullParserException, IOException {
final String splitName;
final String pkgName;
......
final Package pkg = new Package(pkgName);
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifest); //Resources类通过解析器,获取解析数据中的相关R.styleable.AndroidManifest,属性信息sa
pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_versionCode, 0); //从属性信息获取相关属性值
pkg.baseRevisionCode = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_revisionCode, 0);
pkg.mVersionName = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifest_versionName, 0);
if (pkg.mVersionName != null) {
pkg.mVersionName = pkg.mVersionName.intern();
}
pkg.coreApp = parser.getAttributeBooleanValue(null, "coreApp", false);
sa.recycle(); //回收sa资源
return parseBaseApkCommon(pkg, null, res, parser, flags, outError);
}
4. parser开始解析标签
private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,
XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
IOException {
mParseInstrumentationArgs = null;
int type;
boolean foundApp = false;
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifest); //res资源回收后,再重新加载需要资源
String str = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
......
int outerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT //当parser解析的不是END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName(); //获取标签名
if (acceptedTags != null && !acceptedTags.contains(tagName)) {
Slog.w(TAG, "Skipping unsupported element under <manifest>: "
+ tagName + " at " + mArchiveSourcePath + " "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
if (tagName.equals(TAG_APPLICATION)) {
if (foundApp) {
if (RIGID_PARSER) {
outError[0] = "<manifest> has more than one <application>";
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return null;
} else {
Slog.w(TAG, "<manifest> has more than one <application>");
XmlUtils.skipCurrentTag(parser);
continue;
}
}
foundApp = true;
if (!parseBaseApplication(pkg, res, parser, flags, outError)) { //解析application标签
return null;
}
} else if (tagName.equals(TAG_OVERLAY)) {
5. parseBaseApplication解析application标签
private boolean parseBaseApplication(Package owner, Resources res,
XmlResourceParser parser, int flags, String[] outError)
throws XmlPullParserException, IOException {
final ApplicationInfo ai = owner.applicationInfo;
final String pkgName = owner.applicationInfo.packageName;
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifestApplication);
if (!parsePackageItemInfo(owner, ai, outError,
"<application>", sa, false /*nameRequired*/,
com.android.internal.R.styleable.AndroidManifestApplication_name,
com.android.internal.R.styleable.AndroidManifestApplication_label,
com.android.internal.R.styleable.AndroidManifestApplication_icon,
com.android.internal.R.styleable.AndroidManifestApplication_roundIcon,
com.android.internal.R.styleable.AndroidManifestApplication_logo,
com.android.internal.R.styleable.AndroidManifestApplication_banner)) {
sa.recycle();
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
6. parser解析数据
String nodeName = parser.getName(); //获取标签名
if (nodeName.equals("action")) {
String value = parser.getAttributeValue(
ANDROID_RESOURCES, "name"); //获取action标签中属性为name的值,ANDROID_RESOURCES为域名:"http://schemas.android.com/apk/res/android"
String node_value = parser.nextText(); //获取标签中间的数据