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