ManifestDigest.java revision 6c918cec31f396bb19597d107856122173c90594
17767eac3232ba2fb9828766813cdb481d6a97584Dianne Hackborn/* 27767eac3232ba2fb9828766813cdb481d6a97584Dianne Hackborn * Copyright (C) 2012 The Android Open Source Project 37767eac3232ba2fb9828766813cdb481d6a97584Dianne Hackborn * 47767eac3232ba2fb9828766813cdb481d6a97584Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License"); 57767eac3232ba2fb9828766813cdb481d6a97584Dianne Hackborn * you may not use this file except in compliance with the License. 67767eac3232ba2fb9828766813cdb481d6a97584Dianne Hackborn * You may obtain a copy of the License at 77767eac3232ba2fb9828766813cdb481d6a97584Dianne Hackborn * 87767eac3232ba2fb9828766813cdb481d6a97584Dianne Hackborn * http://www.apache.org/licenses/LICENSE-2.0 97767eac3232ba2fb9828766813cdb481d6a97584Dianne Hackborn * 107767eac3232ba2fb9828766813cdb481d6a97584Dianne Hackborn * Unless required by applicable law or agreed to in writing, software 117767eac3232ba2fb9828766813cdb481d6a97584Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS, 127767eac3232ba2fb9828766813cdb481d6a97584Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137767eac3232ba2fb9828766813cdb481d6a97584Dianne Hackborn * See the License for the specific language governing permissions and 147767eac3232ba2fb9828766813cdb481d6a97584Dianne Hackborn * limitations under the License. 157767eac3232ba2fb9828766813cdb481d6a97584Dianne Hackborn */ 167767eac3232ba2fb9828766813cdb481d6a97584Dianne Hackborn 17bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Rootpackage android.content.pm; 18bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 19bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Rootimport android.os.Parcel; 20bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Rootimport android.os.Parcelable; 216c918cec31f396bb19597d107856122173c90594Kenny Rootimport android.util.Slog; 226c918cec31f396bb19597d107856122173c90594Kenny Root 236c918cec31f396bb19597d107856122173c90594Kenny Rootimport java.io.BufferedInputStream; 246c918cec31f396bb19597d107856122173c90594Kenny Rootimport java.io.IOException; 256c918cec31f396bb19597d107856122173c90594Kenny Rootimport java.io.InputStream; 266c918cec31f396bb19597d107856122173c90594Kenny Rootimport java.security.DigestInputStream; 276c918cec31f396bb19597d107856122173c90594Kenny Rootimport java.security.MessageDigest; 286c918cec31f396bb19597d107856122173c90594Kenny Rootimport java.security.NoSuchAlgorithmException; 29bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Rootimport java.util.Arrays; 306c918cec31f396bb19597d107856122173c90594Kenny Root 316c918cec31f396bb19597d107856122173c90594Kenny Rootimport libcore.io.IoUtils; 32bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 33bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root/** 34bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root * Represents the manifest digest for a package. This is suitable for comparison 35bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root * of two packages to know whether the manifests are identical. 36bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root * 37bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root * @hide 38bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root */ 39bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Rootpublic class ManifestDigest implements Parcelable { 406c918cec31f396bb19597d107856122173c90594Kenny Root private static final String TAG = "ManifestDigest"; 416c918cec31f396bb19597d107856122173c90594Kenny Root 42bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root /** The digest of the manifest in our preferred order. */ 43bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root private final byte[] mDigest; 44bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 45bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root /** What we print out first when toString() is called. */ 46bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root private static final String TO_STRING_PREFIX = "ManifestDigest {mDigest="; 47bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 486c918cec31f396bb19597d107856122173c90594Kenny Root /** Digest algorithm to use. */ 496c918cec31f396bb19597d107856122173c90594Kenny Root private static final String DIGEST_ALGORITHM = "SHA-256"; 506c918cec31f396bb19597d107856122173c90594Kenny Root 51bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root ManifestDigest(byte[] digest) { 52bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root mDigest = digest; 53bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 54bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 55bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root private ManifestDigest(Parcel source) { 56bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root mDigest = source.createByteArray(); 57bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 58bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 596c918cec31f396bb19597d107856122173c90594Kenny Root static ManifestDigest fromInputStream(InputStream fileIs) { 606c918cec31f396bb19597d107856122173c90594Kenny Root if (fileIs == null) { 61bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root return null; 62bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 63bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 646c918cec31f396bb19597d107856122173c90594Kenny Root final MessageDigest md; 656c918cec31f396bb19597d107856122173c90594Kenny Root try { 666c918cec31f396bb19597d107856122173c90594Kenny Root md = MessageDigest.getInstance(DIGEST_ALGORITHM); 676c918cec31f396bb19597d107856122173c90594Kenny Root } catch (NoSuchAlgorithmException e) { 686c918cec31f396bb19597d107856122173c90594Kenny Root throw new RuntimeException(DIGEST_ALGORITHM + " must be available", e); 69bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 70bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 716c918cec31f396bb19597d107856122173c90594Kenny Root final DigestInputStream dis = new DigestInputStream(new BufferedInputStream(fileIs), md); 726c918cec31f396bb19597d107856122173c90594Kenny Root try { 736c918cec31f396bb19597d107856122173c90594Kenny Root byte[] readBuffer = new byte[8192]; 746c918cec31f396bb19597d107856122173c90594Kenny Root while (dis.read(readBuffer, 0, readBuffer.length) != -1) { 756c918cec31f396bb19597d107856122173c90594Kenny Root // not using 766c918cec31f396bb19597d107856122173c90594Kenny Root } 776c918cec31f396bb19597d107856122173c90594Kenny Root } catch (IOException e) { 786c918cec31f396bb19597d107856122173c90594Kenny Root Slog.w(TAG, "Could not read manifest"); 79bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root return null; 806c918cec31f396bb19597d107856122173c90594Kenny Root } finally { 816c918cec31f396bb19597d107856122173c90594Kenny Root IoUtils.closeQuietly(dis); 82bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 83bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 846c918cec31f396bb19597d107856122173c90594Kenny Root final byte[] digest = md.digest(); 85bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root return new ManifestDigest(digest); 86bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 87bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 88bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root @Override 89bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root public int describeContents() { 90bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root return 0; 91bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 92bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 93bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root @Override 94bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root public boolean equals(Object o) { 95bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root if (!(o instanceof ManifestDigest)) { 96bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root return false; 97bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 98bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 99bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root final ManifestDigest other = (ManifestDigest) o; 100bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 101bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root return this == other || Arrays.equals(mDigest, other.mDigest); 102bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 103bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 104bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root @Override 105bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root public int hashCode() { 106bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root return Arrays.hashCode(mDigest); 107bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 108bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 109bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root @Override 110bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root public String toString() { 111bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root final StringBuilder sb = new StringBuilder(TO_STRING_PREFIX.length() 112bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root + (mDigest.length * 3) + 1); 113bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 114bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root sb.append(TO_STRING_PREFIX); 115bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 116bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root final int N = mDigest.length; 117bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root for (int i = 0; i < N; i++) { 118bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root final byte b = mDigest[i]; 119bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root IntegralToString.appendByteAsHex(sb, b, false); 120bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root sb.append(','); 121bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 122bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root sb.append('}'); 123bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 124bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root return sb.toString(); 125bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 126bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 127bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root @Override 128bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root public void writeToParcel(Parcel dest, int flags) { 129bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root dest.writeByteArray(mDigest); 130bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 131bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 132bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root public static final Parcelable.Creator<ManifestDigest> CREATOR 133bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root = new Parcelable.Creator<ManifestDigest>() { 134bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root public ManifestDigest createFromParcel(Parcel source) { 135bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root return new ManifestDigest(source); 136bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 137bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 138bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root public ManifestDigest[] newArray(int size) { 139bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root return new ManifestDigest[size]; 140bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 141bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root }; 142bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 143bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root}