1 /* 2 * Copyright 2016, 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 com.android.managedprovisioning.model; 18 19 import static com.android.internal.util.Preconditions.checkArgument; 20 import static com.android.internal.util.Preconditions.checkNotNull; 21 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 import android.support.annotation.Nullable; 25 import android.text.TextUtils; 26 27 import java.util.Arrays; 28 import java.util.Objects; 29 30 import com.android.internal.annotations.Immutable; 31 32 /** 33 * Stores the device admin package download information. 34 */ 35 @Immutable 36 public final class PackageDownloadInfo implements Parcelable { 37 public static final byte[] DEFAULT_PACKAGE_CHECKSUM = new byte[0]; 38 public static final byte[] DEFAULT_SIGNATURE_CHECKSUM = new byte[0]; 39 public static final boolean DEFAULT_PACKAGE_CHECKSUM_SUPPORTS_SHA1 = false; 40 // Always download packages if no minimum version given. 41 public static final int DEFAULT_MINIMUM_VERSION = Integer.MAX_VALUE; 42 43 public static final Parcelable.Creator<PackageDownloadInfo> CREATOR 44 = new Parcelable.Creator<PackageDownloadInfo>() { 45 @Override 46 public PackageDownloadInfo createFromParcel(Parcel in) { 47 return new PackageDownloadInfo(in); 48 } 49 50 @Override 51 public PackageDownloadInfo[] newArray(int size) { 52 return new PackageDownloadInfo[size]; 53 } 54 }; 55 56 /** 57 * Url where the package (.apk) can be downloaded from. {@code null} if there is no download 58 * location specified. 59 */ 60 public final String location; 61 /** Cookie header for http request. */ 62 @Nullable 63 public final String cookieHeader; 64 /** 65 * One of the following two checksums should be non empty. SHA-256 or SHA-1 hash of the 66 * .apk file, or empty array if not used. 67 */ 68 public final byte[] packageChecksum; 69 /** SHA-256 hash of the signature in the .apk file, or empty array if not used. */ 70 public final byte[] signatureChecksum; 71 /** Minimum supported version code of the downloaded package. */ 72 public final int minVersion; 73 /** 74 * If this is false, packageChecksum can only be SHA-256 hash, otherwise SHA-1 is also 75 * supported. 76 */ 77 public final boolean packageChecksumSupportsSha1; 78 79 private PackageDownloadInfo(Builder builder) { 80 location = builder.mLocation; 81 cookieHeader = builder.mCookieHeader; 82 packageChecksum = checkNotNull(builder.mPackageChecksum, "package checksum can't be null"); 83 signatureChecksum = checkNotNull(builder.mSignatureChecksum, 84 "signature checksum can't be null"); 85 minVersion = builder.mMinVersion; 86 packageChecksumSupportsSha1 = builder.mPackageChecksumSupportsSha1; 87 88 validateFields(); 89 } 90 91 private PackageDownloadInfo(Parcel in) { 92 minVersion = in.readInt(); 93 location = in.readString(); 94 cookieHeader = in.readString(); 95 packageChecksum = checkNotNull(in.createByteArray()); 96 signatureChecksum = checkNotNull(in.createByteArray()); 97 packageChecksumSupportsSha1 = in.readInt() == 1; 98 99 validateFields(); 100 } 101 102 private void validateFields() { 103 if (TextUtils.isEmpty(location)) { 104 throw new IllegalArgumentException("Download location must not be empty."); 105 } 106 if (packageChecksum.length == 0 && signatureChecksum.length == 0) { 107 throw new IllegalArgumentException("Package checksum or signature checksum must be " 108 + "provided."); 109 } 110 } 111 112 @Override 113 public int describeContents() { 114 return 0; 115 } 116 117 @Override 118 public void writeToParcel(Parcel out, int flags) { 119 out.writeInt(minVersion); 120 out.writeString(location); 121 out.writeString(cookieHeader); 122 out.writeByteArray(packageChecksum); 123 out.writeByteArray(signatureChecksum); 124 out.writeInt(packageChecksumSupportsSha1 ? 1 : 0); 125 } 126 127 @Override 128 public boolean equals(Object o) { 129 if (this == o) { 130 return true; 131 } 132 if (o == null || getClass() != o.getClass()) { 133 return false; 134 } 135 PackageDownloadInfo that = (PackageDownloadInfo) o; 136 return minVersion == that.minVersion 137 && packageChecksumSupportsSha1 == that.packageChecksumSupportsSha1 138 && Objects.equals(location, that.location) 139 && Objects.equals(cookieHeader, that.cookieHeader) 140 && Arrays.equals(packageChecksum, that.packageChecksum) 141 && Arrays.equals(signatureChecksum, that.signatureChecksum); 142 } 143 144 public final static class Builder { 145 private String mLocation; 146 private String mCookieHeader; 147 private byte[] mPackageChecksum = DEFAULT_PACKAGE_CHECKSUM; 148 private byte[] mSignatureChecksum = DEFAULT_SIGNATURE_CHECKSUM; 149 private int mMinVersion = DEFAULT_MINIMUM_VERSION; 150 private boolean mPackageChecksumSupportsSha1 = DEFAULT_PACKAGE_CHECKSUM_SUPPORTS_SHA1; 151 152 public Builder setLocation(String location) { 153 mLocation = location; 154 return this; 155 } 156 157 public Builder setCookieHeader(String cookieHeader) { 158 mCookieHeader = cookieHeader; 159 return this; 160 } 161 162 public Builder setPackageChecksum(byte[] packageChecksum) { 163 mPackageChecksum = packageChecksum; 164 return this; 165 } 166 167 public Builder setSignatureChecksum(byte[] signatureChecksum) { 168 mSignatureChecksum = signatureChecksum; 169 return this; 170 } 171 172 public Builder setMinVersion(int minVersion) { 173 mMinVersion = minVersion; 174 return this; 175 } 176 177 // TODO: remove once SHA-1 is fully deprecated. 178 public Builder setPackageChecksumSupportsSha1(boolean packageChecksumSupportsSha1) { 179 mPackageChecksumSupportsSha1 = packageChecksumSupportsSha1; 180 return this; 181 } 182 183 public PackageDownloadInfo build() { 184 return new PackageDownloadInfo(this); 185 } 186 187 public static Builder builder() { 188 return new Builder(); 189 } 190 } 191 } 192