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;