Manifest digest stored during package scanning
This allows things that scanned an APK to pass a hash of the manifest to
others that would then be able to compare it.
Change-Id: I465f5edf3acab2a952c3d321c8df2247ffe012ea
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 5f4625b..c61e32f 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -45,6 +45,7 @@
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
+import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
@@ -59,6 +60,9 @@
private static final boolean DEBUG_PARSER = false;
private static final boolean DEBUG_BACKUP = false;
+ /** File name in an APK for the Android manifest. */
+ private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
+
/** @hide */
public static class NewPermissionInfo {
public final String name;
@@ -402,7 +406,7 @@
res = new Resources(assmgr, metrics, null);
assmgr.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Build.VERSION.RESOURCES_SDK_INT);
- parser = assmgr.openXmlResourceParser(cookie, "AndroidManifest.xml");
+ parser = assmgr.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
assetError = false;
} else {
Slog.w(TAG, "Failed adding asset path:"+mArchiveSourcePath);
@@ -484,7 +488,7 @@
// can trust it... we'll just use the AndroidManifest.xml
// to retrieve its signatures, not validating all of the
// files.
- JarEntry jarEntry = jarFile.getJarEntry("AndroidManifest.xml");
+ JarEntry jarEntry = jarFile.getJarEntry(ANDROID_MANIFEST_FILENAME);
certs = loadCertificates(jarFile, jarEntry, readBuffer);
if (certs == null) {
Slog.e(TAG, "Package " + pkg.packageName
@@ -506,21 +510,30 @@
}
}
}
-
} else {
Enumeration<JarEntry> entries = jarFile.entries();
+ final Manifest manifest = jarFile.getManifest();
while (entries.hasMoreElements()) {
final JarEntry je = entries.nextElement();
if (je.isDirectory()) continue;
- if (je.getName().startsWith("META-INF/")) continue;
- final Certificate[] localCerts = loadCertificates(jarFile, je,
- readBuffer);
+ final String name = je.getName();
+
+ if (name.startsWith("META-INF/"))
+ continue;
+
+ if (ANDROID_MANIFEST_FILENAME.equals(name)) {
+ final Attributes attributes = manifest.getAttributes(name);
+ pkg.manifestDigest = ManifestDigest.fromAttributes(attributes);
+ }
+
+ final Certificate[] localCerts = loadCertificates(jarFile, je, readBuffer);
if (DEBUG_JAR) {
Slog.i(TAG, "File " + mArchiveSourcePath + " entry " + je.getName()
+ ": certs=" + certs + " ("
+ (certs != null ? certs.length : 0) + ")");
}
+
if (localCerts == null) {
Slog.e(TAG, "Package " + pkg.packageName
+ " has no certificates at entry "
@@ -609,7 +622,7 @@
return null;
}
- parser = assmgr.openXmlResourceParser(cookie, "AndroidManifest.xml");
+ parser = assmgr.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
} catch (Exception e) {
if (assmgr != null) assmgr.close();
Slog.w(TAG, "Unable to read AndroidManifest.xml of "
@@ -2884,6 +2897,12 @@
public int installLocation;
+ /**
+ * Digest suitable for comparing whether this package's manifest is the
+ * same as another.
+ */
+ public ManifestDigest manifestDigest;
+
public Package(String _name) {
packageName = _name;
applicationInfo.packageName = _name;