Home | History | Annotate | Download | only in model
      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 android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION;
     20 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER;
     21 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM;
     22 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM;
     23 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE;
     24 import static com.android.internal.util.Preconditions.checkNotNull;
     25 
     26 import android.os.Parcel;
     27 import android.os.Parcelable;
     28 import android.os.PersistableBundle;
     29 import android.support.annotation.Nullable;
     30 import android.text.TextUtils;
     31 import com.android.internal.annotations.Immutable;
     32 import com.android.managedprovisioning.common.PersistableBundlable;
     33 import com.android.managedprovisioning.common.StoreUtils;
     34 import java.io.IOException;
     35 import java.util.Arrays;
     36 import java.util.Objects;
     37 import org.xmlpull.v1.XmlPullParser;
     38 import org.xmlpull.v1.XmlPullParserException;
     39 import org.xmlpull.v1.XmlSerializer;
     40 
     41 /**
     42  * Stores the device admin package download information.
     43  */
     44 @Immutable
     45 public 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