remove custom AndroidManifest.xml parsing and instead use PackageParser

This has the advantage, that AndroidManifest.xml is only parsed once.
This commit is contained in:
Julian Winkler
2024-06-10 23:24:29 +02:00
parent f249e1c487
commit b15bf203a7
8 changed files with 126 additions and 232 deletions

View File

@@ -16,12 +16,6 @@
package android.content.pm;
import android.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.util.TypedValue;
/**
* Overall information about the contents of a package. This corresponds
* to all of the information collected from AndroidManifest.xml.
@@ -237,58 +231,6 @@ public class PackageInfo {
*/
public String requiredAccountType;
public PackageInfo() {
applicationInfo = new ApplicationInfo();
try {
XmlResourceParser parser = Context.this_application.getAssets().openXmlResourceParser("AndroidManifest.xml");
for (; parser.getEventType() != XmlResourceParser.END_DOCUMENT; parser.next()) {
if (parser.getEventType() == XmlResourceParser.START_TAG && "manifest".equals(parser.getName())) {
packageName = parser.getAttributeValue(null, "package");
versionCode = parser.getAttributeIntValue("http://schemas.android.com/apk/res/android", "versionCode", -1);
versionName = parser.getAttributeValue("http://schemas.android.com/apk/res/android", "versionName");
}
if (parser.getEventType() == XmlResourceParser.START_TAG && "application".equals(parser.getName())) {
for (; !(parser.getEventType() == XmlResourceParser.END_TAG && "application".equals(parser.getName())); parser.next()) {
if (parser.getEventType() == XmlResourceParser.START_TAG && "meta-data".equals(parser.getName())) {
TypedArray a = Context.this_application.getResources().obtainAttributes(parser, R.styleable.AndroidManifestMetaData);
String metadata_name = a.getString(R.styleable.AndroidManifestMetaData_name);
if (metadata_name == null || !a.hasValue(R.styleable.AndroidManifestMetaData_value)) {
a.recycle();
continue;
}
TypedValue metadata_value = new TypedValue();
a.getValue(R.styleable.AndroidManifestMetaData_value, metadata_value);
a.recycle();
switch(metadata_value.type) {
case TypedValue.TYPE_STRING:
System.out.println("PackageInfo(): applicationInfo.metaData.putString("+metadata_name+", "+metadata_value.string+")");
applicationInfo.metaData.putString(metadata_name, metadata_value.string.toString());
break;
case TypedValue.TYPE_INT_BOOLEAN:
System.out.println("PackageInfo(): applicationInfo.metaData.putBoolean("+metadata_name+", "+(metadata_value.data != 0)+")");
applicationInfo.metaData.putBoolean(metadata_name, metadata_value.data != 0);
break;
case TypedValue.TYPE_INT_DEC:
case TypedValue.TYPE_INT_HEX:
System.out.println("PackageInfo(): applicationInfo.metaData.putInt("+metadata_name+", "+metadata_value.data+")");
applicationInfo.metaData.putInt(metadata_name, metadata_value.data);
break;
default:
System.out.println("PackageInfo(): metaData: "+metadata_name+": type "+metadata_value.type+" not handled!");
break;
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("PackageInfo(): packageName: >"+packageName+"<, versionCode: >"+versionCode+"<, versionName: >"+versionName+"<");
}
public String toString() {
return "PackageInfo{" + Integer.toHexString(System.identityHashCode(this)) + " " + packageName + "}";
}

View File

@@ -27,7 +27,6 @@ import android.content.res.Resources;
import android.content.res.XmlResourceParser;
// import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.UserHandle;
import android.util.AndroidException;
@@ -36,6 +35,7 @@ import android.util.Slog;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
class IPackageInstallObserver {}
@@ -1374,7 +1374,7 @@ public class PackageManager {
public PackageManager() {
package_info = new PackageInfo();
package_info = PackageParser.generatePackageInfo(Context.pkg, new int[0], 0, 0, 0, new HashSet<>(), new PackageUserState());
}
/**
@@ -1696,32 +1696,12 @@ public class PackageManager {
*/
public ProviderInfo getProviderInfo(ComponentName component,
int flags) throws Exception {
ProviderInfo providerInfo = new ProviderInfo();
if ((flags & GET_META_DATA) == GET_META_DATA) {
String cls = component.getClassName();
XmlResourceParser parser = Context.this_application.getAssets().openXmlResourceParser("AndroidManifest.xml");
for(; parser.getEventType() != XmlResourceParser.END_DOCUMENT; parser.next()) {
if (parser.getEventType() == XmlResourceParser.START_TAG && "provider".equals(parser.getName())) {
String providerName = parser.getAttributeValue("http://schemas.android.com/apk/res/android", "name");
if (providerName.startsWith("."))
providerName = Context.this_application.getPackageName() + providerName;
if (!providerName.equals(cls))
continue;
Bundle bundle = new Bundle();
for (; !(parser.getEventType() == XmlResourceParser.END_TAG && "provider".equals(parser.getName())); parser.next()) {
if (parser.getEventType() == XmlResourceParser.START_TAG && "meta-data".equals(parser.getName())) {
String metaName = parser.getAttributeValue("http://schemas.android.com/apk/res/android", "name");
String metaValue = parser.getAttributeValue("http://schemas.android.com/apk/res/android", "value");
bundle.putString(metaName, metaValue);
}
}
providerInfo.metaData = bundle;
break;
}
for (PackageParser.Provider p : Context.pkg.providers) {
if (p.className.equals(component.getClassName())) {
return p.info;
}
parser.close();
}
return providerInfo;
throw new NameNotFoundException();
}
/**
@@ -2428,27 +2408,12 @@ public class PackageManager {
* @throws Exception
*/
public ProviderInfo resolveContentProvider(String authority, int flags) throws Exception {
ProviderInfo providerInfo = new ProviderInfo();
XmlResourceParser parser = Context.this_application.getAssets().openXmlResourceParser("AndroidManifest.xml");
for (; parser.getEventType() != XmlResourceParser.END_DOCUMENT; parser.next()) {
if (parser.getEventType() == XmlResourceParser.START_TAG && "provider".equals(parser.getName())) {
String providerAuthority = parser.getAttributeValue("http://schemas.android.com/apk/res/android", "authorities");
if (providerAuthority.startsWith("."))
providerAuthority = Context.this_application.getPackageName() + providerAuthority;
if (!providerAuthority.equals(authority))
continue;
for (; !(parser.getEventType() == XmlResourceParser.END_TAG && "provider".equals(parser.getName())); parser.next()) {
if (parser.getEventType() == XmlResourceParser.START_TAG && "meta-data".equals(parser.getName())) {
String metaName = parser.getAttributeValue("http://schemas.android.com/apk/res/android", "name");
int metaRes = parser.getAttributeResourceValue("http://schemas.android.com/apk/res/android", "resource", -1);
providerInfo.metaData.putInt(metaName, metaRes);
}
}
break;
}
for (PackageParser.Provider p : Context.pkg.providers) {
if (p.info.authority.equals(authority))
return p.info;
}
parser.close();
return providerInfo;
throw new Exception("Provider not found: " + authority);
}
/**

View File

@@ -17,6 +17,7 @@
package android.content.pm;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.AssetManager;
import android.content.res.Configuration;
@@ -936,7 +937,7 @@ public class PackageParser {
return new Signature(sig);
}
private Package parsePackage(
public Package parsePackage(
Resources res, XmlResourceParser parser, int flags, String[] outError)
throws XmlPullParserException, IOException {
AttributeSet attrs = parser;
@@ -1162,9 +1163,9 @@ public class PackageParser {
return null;
}
} else if (minVers > SDK_VERSION) {
outError[0] = "Requires newer sdk version #" + minVers + " (current version is #" + SDK_VERSION + ")";
mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
return null;
// outError[0] = "Requires newer sdk version #" + minVers + " (current version is #" + SDK_VERSION + ")";
// mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
// return null;
}
if (targetCode != null) {
@@ -2203,6 +2204,62 @@ public class PackageParser {
return true;
}
private boolean parseIntent(Resources res, XmlPullParser parser, AttributeSet attrs, boolean allowGlobs,
boolean allowAutoVerify, IntentInfo outInfo, String[] outError)
throws XmlPullParserException, IOException {
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifestIntentFilter);
TypedValue v = sa.peekValue(
com.android.internal.R.styleable.AndroidManifestIntentFilter_label);
if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
outInfo.nonLocalizedLabel = v.coerceToString();
}
outInfo.icon = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0);
outInfo.logo = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0);
sa.recycle();
int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String nodeName = parser.getName();
if (nodeName.equals("action")) {
String value = parser.getAttributeValue(
ANDROID_RESOURCES, "name");
if (value == null || value == "") {
outError[0] = "No value supplied for <android:name>";
return false;
}
XmlUtils.skipCurrentTag(parser);
outInfo.addAction(value);
} else if (nodeName.equals("category")) {
String value = parser.getAttributeValue(
ANDROID_RESOURCES, "name");
if (value == null || value == "") {
outError[0] = "No value supplied for <android:name>";
return false;
}
XmlUtils.skipCurrentTag(parser);
} else if (nodeName.equals("data")) {
XmlUtils.skipCurrentTag(parser);
} else if (!RIGID_PARSER) {
Slog.w(TAG, "Unknown element under <intent-filter>: "
+ parser.getName() + " at " + mArchiveSourcePath + " "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
} else {
outError[0] = "Bad element under <intent-filter>: " + parser.getName();
return false;
}
}
return true;
}
private Activity parseActivity(Package owner, Resources res,
XmlPullParser parser, AttributeSet attrs, int flags, String[] outError,
boolean receiver, boolean hardwareAccelerated)
@@ -2405,7 +2462,20 @@ public class PackageParser {
continue;
}
if (parser.getName().equals("meta-data")) {
if (parser.getName().equals("intent-filter")) {
ActivityIntentInfo intent = new ActivityIntentInfo(a);
if (!parseIntent(res, parser, attrs, true /*allowGlobs*/, true /*allowAutoVerify*/,
intent, outError)) {
return null;
}
if (intent.countActions() == 0) {
Slog.w(TAG, "No actions in intent filter at "
+ mArchiveSourcePath + " "
+ parser.getPositionDescription());
} else {
a.intents.add(intent);
}
} else if (parser.getName().equals("meta-data")) {
if ((a.metaData = parseMetaData(res, parser, attrs, a.metaData,
outError)) == null) {
return null;
@@ -2721,6 +2791,7 @@ public class PackageParser {
outInfo.metaData, outError)) == null) {
return false;
}
outInfo.info.metaData = outInfo.metaData;
} else if (parser.getName().equals("grant-uri-permission")) {
TypedArray sa = res.obtainAttributes(attrs,