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 
PackageDownloadInfo(Builder builder)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 
PackageDownloadInfo(Parcel in)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 
validateFields()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
describeContents()113     public int describeContents() {
114         return 0;
115     }
116 
117     @Override
writeToParcel(Parcel out, int flags)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
equals(Object o)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 
setLocation(String location)152         public Builder setLocation(String location) {
153             mLocation = location;
154             return this;
155         }
156 
setCookieHeader(String cookieHeader)157         public Builder setCookieHeader(String cookieHeader) {
158             mCookieHeader = cookieHeader;
159             return this;
160         }
161 
setPackageChecksum(byte[] packageChecksum)162         public Builder setPackageChecksum(byte[] packageChecksum) {
163             mPackageChecksum = packageChecksum;
164             return this;
165         }
166 
setSignatureChecksum(byte[] signatureChecksum)167         public Builder setSignatureChecksum(byte[] signatureChecksum) {
168             mSignatureChecksum = signatureChecksum;
169             return this;
170         }
171 
setMinVersion(int minVersion)172         public Builder setMinVersion(int minVersion) {
173             mMinVersion = minVersion;
174             return this;
175         }
176 
177         // TODO: remove once SHA-1 is fully deprecated.
setPackageChecksumSupportsSha1(boolean packageChecksumSupportsSha1)178         public Builder setPackageChecksumSupportsSha1(boolean packageChecksumSupportsSha1) {
179             mPackageChecksumSupportsSha1 = packageChecksumSupportsSha1;
180             return this;
181         }
182 
build()183         public PackageDownloadInfo build() {
184             return new PackageDownloadInfo(this);
185         }
186 
builder()187         public static Builder builder() {
188             return new Builder();
189         }
190     }
191 }
192