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 19d5a5b5a547462f3e7c6315a501909bce2418ba86Jeff Brownimport android.annotation.SystemApi; 20bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Rootimport android.os.Parcel; 21bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Rootimport android.os.Parcelable; 226c918cec31f396bb19597d107856122173c90594Kenny Rootimport android.util.Slog; 236c918cec31f396bb19597d107856122173c90594Kenny Root 246c918cec31f396bb19597d107856122173c90594Kenny Rootimport java.io.BufferedInputStream; 256c918cec31f396bb19597d107856122173c90594Kenny Rootimport java.io.IOException; 266c918cec31f396bb19597d107856122173c90594Kenny Rootimport java.io.InputStream; 276c918cec31f396bb19597d107856122173c90594Kenny Rootimport java.security.DigestInputStream; 286c918cec31f396bb19597d107856122173c90594Kenny Rootimport java.security.MessageDigest; 296c918cec31f396bb19597d107856122173c90594Kenny Rootimport java.security.NoSuchAlgorithmException; 30bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Rootimport java.util.Arrays; 316c918cec31f396bb19597d107856122173c90594Kenny Root 326c918cec31f396bb19597d107856122173c90594Kenny Rootimport libcore.io.IoUtils; 33bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 34bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root/** 35bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root * Represents the manifest digest for a package. This is suitable for comparison 36bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root * of two packages to know whether the manifests are identical. 37bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root * 38bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root * @hide 39bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root */ 40d5a5b5a547462f3e7c6315a501909bce2418ba86Jeff Brown@SystemApi 41bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Rootpublic class ManifestDigest implements Parcelable { 426c918cec31f396bb19597d107856122173c90594Kenny Root private static final String TAG = "ManifestDigest"; 436c918cec31f396bb19597d107856122173c90594Kenny Root 44bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root /** The digest of the manifest in our preferred order. */ 45bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root private final byte[] mDigest; 46bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 47bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root /** What we print out first when toString() is called. */ 48bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root private static final String TO_STRING_PREFIX = "ManifestDigest {mDigest="; 49bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 506c918cec31f396bb19597d107856122173c90594Kenny Root /** Digest algorithm to use. */ 516c918cec31f396bb19597d107856122173c90594Kenny Root private static final String DIGEST_ALGORITHM = "SHA-256"; 526c918cec31f396bb19597d107856122173c90594Kenny Root 53bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root ManifestDigest(byte[] digest) { 54bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root mDigest = digest; 55bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 56bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 57bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root private ManifestDigest(Parcel source) { 58bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root mDigest = source.createByteArray(); 59bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 60bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 616c918cec31f396bb19597d107856122173c90594Kenny Root static ManifestDigest fromInputStream(InputStream fileIs) { 626c918cec31f396bb19597d107856122173c90594Kenny Root if (fileIs == null) { 63bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root return null; 64bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 65bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 666c918cec31f396bb19597d107856122173c90594Kenny Root final MessageDigest md; 676c918cec31f396bb19597d107856122173c90594Kenny Root try { 686c918cec31f396bb19597d107856122173c90594Kenny Root md = MessageDigest.getInstance(DIGEST_ALGORITHM); 696c918cec31f396bb19597d107856122173c90594Kenny Root } catch (NoSuchAlgorithmException e) { 706c918cec31f396bb19597d107856122173c90594Kenny Root throw new RuntimeException(DIGEST_ALGORITHM + " must be available", e); 71bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 72bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 736c918cec31f396bb19597d107856122173c90594Kenny Root final DigestInputStream dis = new DigestInputStream(new BufferedInputStream(fileIs), md); 746c918cec31f396bb19597d107856122173c90594Kenny Root try { 756c918cec31f396bb19597d107856122173c90594Kenny Root byte[] readBuffer = new byte[8192]; 766c918cec31f396bb19597d107856122173c90594Kenny Root while (dis.read(readBuffer, 0, readBuffer.length) != -1) { 776c918cec31f396bb19597d107856122173c90594Kenny Root // not using 786c918cec31f396bb19597d107856122173c90594Kenny Root } 796c918cec31f396bb19597d107856122173c90594Kenny Root } catch (IOException e) { 806c918cec31f396bb19597d107856122173c90594Kenny Root Slog.w(TAG, "Could not read manifest"); 81bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root return null; 826c918cec31f396bb19597d107856122173c90594Kenny Root } finally { 836c918cec31f396bb19597d107856122173c90594Kenny Root IoUtils.closeQuietly(dis); 84bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 85bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 866c918cec31f396bb19597d107856122173c90594Kenny Root final byte[] digest = md.digest(); 87bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root return new ManifestDigest(digest); 88bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 89bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 90bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root @Override 91bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root public int describeContents() { 92bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root return 0; 93bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 94bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 95bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root @Override 96bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root public boolean equals(Object o) { 97bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root if (!(o instanceof ManifestDigest)) { 98bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root return false; 99bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 100bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 101bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root final ManifestDigest other = (ManifestDigest) o; 102bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 103bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root return this == other || Arrays.equals(mDigest, other.mDigest); 104bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 105bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 106bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root @Override 107bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root public int hashCode() { 108bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root return Arrays.hashCode(mDigest); 109bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 110bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 111bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root @Override 112bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root public String toString() { 113bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root final StringBuilder sb = new StringBuilder(TO_STRING_PREFIX.length() 114bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root + (mDigest.length * 3) + 1); 115bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 116bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root sb.append(TO_STRING_PREFIX); 117bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 118bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root final int N = mDigest.length; 119bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root for (int i = 0; i < N; i++) { 120bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root final byte b = mDigest[i]; 121bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root IntegralToString.appendByteAsHex(sb, b, false); 122bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root sb.append(','); 123bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 124bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root sb.append('}'); 125bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 126bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root return sb.toString(); 127bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 128bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 129bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root @Override 130bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root public void writeToParcel(Parcel dest, int flags) { 131bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root dest.writeByteArray(mDigest); 132bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 133bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 134bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root public static final Parcelable.Creator<ManifestDigest> CREATOR 135bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root = new Parcelable.Creator<ManifestDigest>() { 136bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root public ManifestDigest createFromParcel(Parcel source) { 137bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root return new ManifestDigest(source); 138bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 139bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 140bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root public ManifestDigest[] newArray(int size) { 141bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root return new ManifestDigest[size]; 142bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root } 143bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root }; 144bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root 145bcc954d772e8cd5ef640060cbc0be50e7e4778f2Kenny Root}