Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit de1175db authored by Kenny Root's avatar Kenny Root
Browse files

resolved conflicts for merge of 0afa8b36 to master

Change-Id: I09a453ab5dbad58e3dc0858972e222a34d53b282
parents 0147afa7 0afa8b36
Loading
Loading
Loading
Loading
+33 −20
Original line number Original line Diff line number Diff line
@@ -18,10 +18,17 @@ package android.content.pm;


import android.os.Parcel;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Parcelable;
import android.util.Base64;
import android.util.Slog;


import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Arrays;
import java.util.jar.Attributes;

import libcore.io.IoUtils;


/**
/**
 * Represents the manifest digest for a package. This is suitable for comparison
 * Represents the manifest digest for a package. This is suitable for comparison
@@ -30,17 +37,17 @@ import java.util.jar.Attributes;
 * @hide
 * @hide
 */
 */
public class ManifestDigest implements Parcelable {
public class ManifestDigest implements Parcelable {
    private static final String TAG = "ManifestDigest";

    /** The digest of the manifest in our preferred order. */
    /** The digest of the manifest in our preferred order. */
    private final byte[] mDigest;
    private final byte[] mDigest;


    /** Digest field names to look for in preferred order. */
    private static final String[] DIGEST_TYPES = {
            "SHA1-Digest", "SHA-Digest", "MD5-Digest",
    };

    /** What we print out first when toString() is called. */
    /** What we print out first when toString() is called. */
    private static final String TO_STRING_PREFIX = "ManifestDigest {mDigest=";
    private static final String TO_STRING_PREFIX = "ManifestDigest {mDigest=";


    /** Digest algorithm to use. */
    private static final String DIGEST_ALGORITHM = "SHA-256";

    ManifestDigest(byte[] digest) {
    ManifestDigest(byte[] digest) {
        mDigest = digest;
        mDigest = digest;
    }
    }
@@ -49,26 +56,32 @@ public class ManifestDigest implements Parcelable {
        mDigest = source.createByteArray();
        mDigest = source.createByteArray();
    }
    }


    static ManifestDigest fromAttributes(Attributes attributes) {
    static ManifestDigest fromInputStream(InputStream fileIs) {
        if (attributes == null) {
        if (fileIs == null) {
            return null;
            return null;
        }
        }


        String encodedDigest = null;
        final MessageDigest md;

        try {
        for (int i = 0; i < DIGEST_TYPES.length; i++) {
            md = MessageDigest.getInstance(DIGEST_ALGORITHM);
            final String value = attributes.getValue(DIGEST_TYPES[i]);
        } catch (NoSuchAlgorithmException e) {
            if (value != null) {
            throw new RuntimeException(DIGEST_ALGORITHM + " must be available", e);
                encodedDigest = value;
                break;
            }
        }
        }


        if (encodedDigest == null) {
        final DigestInputStream dis = new DigestInputStream(new BufferedInputStream(fileIs), md);
        try {
            byte[] readBuffer = new byte[8192];
            while (dis.read(readBuffer, 0, readBuffer.length) != -1) {
                // not using
            }
        } catch (IOException e) {
            Slog.w(TAG, "Could not read manifest");
            return null;
            return null;
        } finally {
            IoUtils.closeQuietly(dis);
        }
        }


        final byte[] digest = Base64.decode(encodedDigest, Base64.DEFAULT);
        final byte[] digest = md.digest();
        return new ManifestDigest(digest);
        return new ManifestDigest(digest);
    }
    }


+25 −6
Original line number Original line Diff line number Diff line
@@ -24,7 +24,6 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.content.res.XmlResourceParser;
import android.os.Binder;
import android.os.Build;
import android.os.Build;
import android.os.Bundle;
import android.os.Bundle;
import android.os.PatternMatcher;
import android.os.PatternMatcher;
@@ -60,10 +59,9 @@ import java.util.Iterator;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Map;
import java.util.Set;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;


import com.android.internal.util.XmlUtils;
import com.android.internal.util.XmlUtils;


@@ -573,6 +571,28 @@ public class PackageParser {
        return pkg;
        return pkg;
    }
    }


    /**
     * Gathers the {@link ManifestDigest} for {@code pkg} if it exists in the
     * APK. If it successfully scanned the package and found the
     * {@code AndroidManifest.xml}, {@code true} is returned.
     */
    public boolean collectManifestDigest(Package pkg) {
        try {
            final JarFile jarFile = new JarFile(mArchiveSourcePath);
            try {
                final ZipEntry je = jarFile.getEntry(ANDROID_MANIFEST_FILENAME);
                if (je != null) {
                    pkg.manifestDigest = ManifestDigest.fromInputStream(jarFile.getInputStream(je));
                }
            } finally {
                jarFile.close();
            }
            return true;
        } catch (IOException e) {
            return false;
        }
    }

    public boolean collectCertificates(Package pkg, int flags) {
    public boolean collectCertificates(Package pkg, int flags) {
        pkg.mSignatures = null;
        pkg.mSignatures = null;


@@ -624,7 +644,6 @@ public class PackageParser {
                }
                }
            } else {
            } else {
                Enumeration<JarEntry> entries = jarFile.entries();
                Enumeration<JarEntry> entries = jarFile.entries();
                final Manifest manifest = jarFile.getManifest();
                while (entries.hasMoreElements()) {
                while (entries.hasMoreElements()) {
                    final JarEntry je = entries.nextElement();
                    final JarEntry je = entries.nextElement();
                    if (je.isDirectory()) continue;
                    if (je.isDirectory()) continue;
@@ -635,8 +654,8 @@ public class PackageParser {
                        continue;
                        continue;


                    if (ANDROID_MANIFEST_FILENAME.equals(name)) {
                    if (ANDROID_MANIFEST_FILENAME.equals(name)) {
                        final Attributes attributes = manifest.getAttributes(name);
                        pkg.manifestDigest =
                        pkg.manifestDigest = ManifestDigest.fromAttributes(attributes);
                                ManifestDigest.fromInputStream(jarFile.getInputStream(je));
                    }
                    }


                    final Certificate[] localCerts = loadCertificates(jarFile, je, readBuffer);
                    final Certificate[] localCerts = loadCertificates(jarFile, je, readBuffer);
+27 −40
Original line number Original line Diff line number Diff line
@@ -18,64 +18,51 @@ package android.content.pm;


import android.os.Parcel;
import android.os.Parcel;
import android.test.AndroidTestCase;
import android.test.AndroidTestCase;
import android.util.Base64;


import java.util.jar.Attributes;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;


public class ManifestDigestTest extends AndroidTestCase {
public class ManifestDigestTest extends AndroidTestCase {
    private static final byte[] DIGEST_1 = {
    private static final byte[] MESSAGE_1 = {
            (byte) 0x00, (byte) 0xAA, (byte) 0x55, (byte) 0xFF
            (byte) 0x00, (byte) 0xAA, (byte) 0x55, (byte) 0xFF
    };
    };


    private static final String DIGEST_1_STR = Base64.encodeToString(DIGEST_1, Base64.DEFAULT);
    public void testManifestDigest_FromInputStream_Null() {

    private static final byte[] DIGEST_2 = {
            (byte) 0x0A, (byte) 0xA5, (byte) 0xF0, (byte) 0x5A
    };

    private static final String DIGEST_2_STR = Base64.encodeToString(DIGEST_2, Base64.DEFAULT);

    private static final Attributes.Name SHA1_DIGEST = new Attributes.Name("SHA1-Digest");

    private static final Attributes.Name MD5_DIGEST = new Attributes.Name("MD5-Digest");

    public void testManifestDigest_FromAttributes_Null() {
        assertNull("Attributes were null, so ManifestDigest.fromAttributes should return null",
        assertNull("Attributes were null, so ManifestDigest.fromAttributes should return null",
                ManifestDigest.fromAttributes(null));
                ManifestDigest.fromInputStream(null));
    }
    }


    public void testManifestDigest_FromAttributes_NoAttributes() {
    public void testManifestDigest_FromInputStream_ThrowsIoException() {
        Attributes a = new Attributes();
        InputStream is = new InputStream() {

            @Override
        assertNull("There were no attributes to extract, so ManifestDigest should be null",
            public int read() throws IOException {
                ManifestDigest.fromAttributes(a));
                throw new IOException();
            }
            }
        };


    public void testManifestDigest_FromAttributes_SHA1PreferredOverMD5() {
        assertNull("InputStream threw exception, so ManifestDigest should be null",
        Attributes a = new Attributes();
                ManifestDigest.fromInputStream(is));
        a.put(SHA1_DIGEST, DIGEST_1_STR);
    }

        a.put(MD5_DIGEST, DIGEST_2_STR);

        ManifestDigest fromAttributes = ManifestDigest.fromAttributes(a);


        assertNotNull("A valid ManifestDigest should be returned", fromAttributes);
    public void testManifestDigest_Equals() throws Exception {
        InputStream is = new ByteArrayInputStream(MESSAGE_1);


        ManifestDigest created = new ManifestDigest(DIGEST_1);
        ManifestDigest expected =
                new ManifestDigest(MessageDigest.getInstance("SHA-256").digest(MESSAGE_1));


        assertEquals("SHA-1 should be preferred over MD5: " + created.toString() + " vs. "
        ManifestDigest actual = ManifestDigest.fromInputStream(is);
                + fromAttributes.toString(), created, fromAttributes);
        assertEquals(expected, actual);


        assertEquals("Hash codes should be the same: " + created.toString() + " vs. "
        ManifestDigest unexpected = new ManifestDigest(new byte[0]);
                + fromAttributes.toString(), created.hashCode(), fromAttributes
        assertFalse(unexpected.equals(actual));
                .hashCode());
    }
    }


    public void testManifestDigest_Parcel() {
    public void testManifestDigest_Parcel() throws Exception {
        Attributes a = new Attributes();
        InputStream is = new ByteArrayInputStream(MESSAGE_1);
        a.put(SHA1_DIGEST, DIGEST_1_STR);


        ManifestDigest digest = ManifestDigest.fromAttributes(a);
        ManifestDigest digest = ManifestDigest.fromInputStream(is);


        Parcel p = Parcel.obtain();
        Parcel p = Parcel.obtain();
        digest.writeToParcel(p, 0);
        digest.writeToParcel(p, 0);