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.annotation.SystemApi; 20 import android.os.Parcel; 21 import android.os.Parcelable; 22 import android.util.Slog; 23 24 import java.io.BufferedInputStream; 25 import java.io.IOException; 26 import java.io.InputStream; 27 import java.security.DigestInputStream; 28 import java.security.MessageDigest; 29 import java.security.NoSuchAlgorithmException; 30 import java.util.Arrays; 31 32 import libcore.io.IoUtils; 33 34 /** 35 * Represents the manifest digest for a package. This is suitable for comparison 36 * of two packages to know whether the manifests are identical. 37 * 38 * @hide 39 */ 40 @SystemApi 41 public class ManifestDigest implements Parcelable { 42 private static final String TAG = "ManifestDigest"; 43 44 /** The digest of the manifest in our preferred order. */ 45 private final byte[] mDigest; 46 47 /** What we print out first when toString() is called. */ 48 private static final String TO_STRING_PREFIX = "ManifestDigest {mDigest="; 49 50 /** Digest algorithm to use. */ 51 private static final String DIGEST_ALGORITHM = "SHA-256"; 52 53 ManifestDigest(byte[] digest) { 54 mDigest = digest; 55 } 56 57 private ManifestDigest(Parcel source) { 58 mDigest = source.createByteArray(); 59 } 60 61 static ManifestDigest fromInputStream(InputStream fileIs) { 62 if (fileIs == null) { 63 return null; 64 } 65 66 final MessageDigest md; 67 try { 68 md = MessageDigest.getInstance(DIGEST_ALGORITHM); 69 } catch (NoSuchAlgorithmException e) { 70 throw new RuntimeException(DIGEST_ALGORITHM + " must be available", e); 71 } 72 73 final DigestInputStream dis = new DigestInputStream(new BufferedInputStream(fileIs), md); 74 try { 75 byte[] readBuffer = new byte[8192]; 76 while (dis.read(readBuffer, 0, readBuffer.length) != -1) { 77 // not using 78 } 79 } catch (IOException e) { 80 Slog.w(TAG, "Could not read manifest"); 81 return null; 82 } finally { 83 IoUtils.closeQuietly(dis); 84 } 85 86 final byte[] digest = md.digest(); 87 return new ManifestDigest(digest); 88 } 89 90 @Override 91 public int describeContents() { 92 return 0; 93 } 94 95 @Override 96 public boolean equals(Object o) { 97 if (!(o instanceof ManifestDigest)) { 98 return false; 99 } 100 101 final ManifestDigest other = (ManifestDigest) o; 102 103 return this == other || Arrays.equals(mDigest, other.mDigest); 104 } 105 106 @Override 107 public int hashCode() { 108 return Arrays.hashCode(mDigest); 109 } 110 111 @Override 112 public String toString() { 113 final StringBuilder sb = new StringBuilder(TO_STRING_PREFIX.length() 114 + (mDigest.length * 3) + 1); 115 116 sb.append(TO_STRING_PREFIX); 117 118 final int N = mDigest.length; 119 for (int i = 0; i < N; i++) { 120 final byte b = mDigest[i]; 121 IntegralToString.appendByteAsHex(sb, b, false); 122 sb.append(','); 123 } 124 sb.append('}'); 125 126 return sb.toString(); 127 } 128 129 @Override 130 public void writeToParcel(Parcel dest, int flags) { 131 dest.writeByteArray(mDigest); 132 } 133 134 public static final Parcelable.Creator<ManifestDigest> CREATOR 135 = new Parcelable.Creator<ManifestDigest>() { 136 public ManifestDigest createFromParcel(Parcel source) { 137 return new ManifestDigest(source); 138 } 139 140 public ManifestDigest[] newArray(int size) { 141 return new ManifestDigest[size]; 142 } 143 }; 144 145 }