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 17package android.content.pm; 18 19import android.os.Parcel; 20import android.os.Parcelable; 21import android.util.Base64; 22 23import java.util.Arrays; 24import java.util.jar.Attributes; 25 26/** 27 * Represents the manifest digest for a package. This is suitable for comparison 28 * of two packages to know whether the manifests are identical. 29 * 30 * @hide 31 */ 32public class ManifestDigest implements Parcelable { 33 /** The digest of the manifest in our preferred order. */ 34 private final byte[] mDigest; 35 36 /** Digest field names to look for in preferred order. */ 37 private static final String[] DIGEST_TYPES = { 38 "SHA1-Digest", "SHA-Digest", "MD5-Digest", 39 }; 40 41 /** What we print out first when toString() is called. */ 42 private static final String TO_STRING_PREFIX = "ManifestDigest {mDigest="; 43 44 ManifestDigest(byte[] digest) { 45 mDigest = digest; 46 } 47 48 private ManifestDigest(Parcel source) { 49 mDigest = source.createByteArray(); 50 } 51 52 static ManifestDigest fromAttributes(Attributes attributes) { 53 if (attributes == null) { 54 return null; 55 } 56 57 String encodedDigest = null; 58 59 for (int i = 0; i < DIGEST_TYPES.length; i++) { 60 final String value = attributes.getValue(DIGEST_TYPES[i]); 61 if (value != null) { 62 encodedDigest = value; 63 break; 64 } 65 } 66 67 if (encodedDigest == null) { 68 return null; 69 } 70 71 final byte[] digest = Base64.decode(encodedDigest, Base64.DEFAULT); 72 return new ManifestDigest(digest); 73 } 74 75 @Override 76 public int describeContents() { 77 return 0; 78 } 79 80 @Override 81 public boolean equals(Object o) { 82 if (!(o instanceof ManifestDigest)) { 83 return false; 84 } 85 86 final ManifestDigest other = (ManifestDigest) o; 87 88 return this == other || Arrays.equals(mDigest, other.mDigest); 89 } 90 91 @Override 92 public int hashCode() { 93 return Arrays.hashCode(mDigest); 94 } 95 96 @Override 97 public String toString() { 98 final StringBuilder sb = new StringBuilder(TO_STRING_PREFIX.length() 99 + (mDigest.length * 3) + 1); 100 101 sb.append(TO_STRING_PREFIX); 102 103 final int N = mDigest.length; 104 for (int i = 0; i < N; i++) { 105 final byte b = mDigest[i]; 106 IntegralToString.appendByteAsHex(sb, b, false); 107 sb.append(','); 108 } 109 sb.append('}'); 110 111 return sb.toString(); 112 } 113 114 @Override 115 public void writeToParcel(Parcel dest, int flags) { 116 dest.writeByteArray(mDigest); 117 } 118 119 public static final Parcelable.Creator<ManifestDigest> CREATOR 120 = new Parcelable.Creator<ManifestDigest>() { 121 public ManifestDigest createFromParcel(Parcel source) { 122 return new ManifestDigest(source); 123 } 124 125 public ManifestDigest[] newArray(int size) { 126 return new ManifestDigest[size]; 127 } 128 }; 129 130}