1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.content.pm; 18 19 import android.os.Parcel; 20 import android.os.Parcelable; 21 import android.util.Slog; 22 23 import java.io.BufferedInputStream; 24 import java.io.IOException; 25 import java.io.InputStream; 26 import java.security.DigestInputStream; 27 import java.security.MessageDigest; 28 import java.security.NoSuchAlgorithmException; 29 import java.util.Arrays; 30 31 import libcore.io.IoUtils; 32 33 /** 34 * Represents the manifest digest for a package. This is suitable for comparison 35 * of two packages to know whether the manifests are identical. 36 * 37 * @hide 38 */ 39 public class ManifestDigest implements Parcelable { 40 private static final String TAG = "ManifestDigest"; 41 42 /** The digest of the manifest in our preferred order. */ 43 private final byte[] mDigest; 44 45 /** What we print out first when toString() is called. */ 46 private static final String TO_STRING_PREFIX = "ManifestDigest {mDigest="; 47 48 /** Digest algorithm to use. */ 49 private static final String DIGEST_ALGORITHM = "SHA-256"; 50 51 ManifestDigest(byte[] digest) { 52 mDigest = digest; 53 } 54 55 private ManifestDigest(Parcel source) { 56 mDigest = source.createByteArray(); 57 } 58 59 static ManifestDigest fromInputStream(InputStream fileIs) { 60 if (fileIs == null) { 61 return null; 62 } 63 64 final MessageDigest md; 65 try { 66 md = MessageDigest.getInstance(DIGEST_ALGORITHM); 67 } catch (NoSuchAlgorithmException e) { 68 throw new RuntimeException(DIGEST_ALGORITHM + " must be available", e); 69 } 70 71 final DigestInputStream dis = new DigestInputStream(new BufferedInputStream(fileIs), md); 72 try { 73 byte[] readBuffer = new byte[8192]; 74 while (dis.read(readBuffer, 0, readBuffer.length) != -1) { 75 // not using 76 } 77 } catch (IOException e) { 78 Slog.w(TAG, "Could not read manifest"); 79 return null; 80 } finally { 81 IoUtils.closeQuietly(dis); 82 } 83 84 final byte[] digest = md.digest(); 85 return new ManifestDigest(digest); 86 } 87 88 @Override 89 public int describeContents() { 90 return 0; 91 } 92 93 @Override 94 public boolean equals(Object o) { 95 if (!(o instanceof ManifestDigest)) { 96 return false; 97 } 98 99 final ManifestDigest other = (ManifestDigest) o; 100 101 return this == other || Arrays.equals(mDigest, other.mDigest); 102 } 103 104 @Override 105 public int hashCode() { 106 return Arrays.hashCode(mDigest); 107 } 108 109 @Override 110 public String toString() { 111 final StringBuilder sb = new StringBuilder(TO_STRING_PREFIX.length() 112 + (mDigest.length * 3) + 1); 113 114 sb.append(TO_STRING_PREFIX); 115 116 final int N = mDigest.length; 117 for (int i = 0; i < N; i++) { 118 final byte b = mDigest[i]; 119 IntegralToString.appendByteAsHex(sb, b, false); 120 sb.append(','); 121 } 122 sb.append('}'); 123 124 return sb.toString(); 125 } 126 127 @Override 128 public void writeToParcel(Parcel dest, int flags) { 129 dest.writeByteArray(mDigest); 130 } 131 132 public static final Parcelable.Creator<ManifestDigest> CREATOR 133 = new Parcelable.Creator<ManifestDigest>() { 134 public ManifestDigest createFromParcel(Parcel source) { 135 return new ManifestDigest(source); 136 } 137 138 public ManifestDigest[] newArray(int size) { 139 return new ManifestDigest[size]; 140 } 141 }; 142 143 }