Home | History | Annotate | Download | only in pm
      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 }