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 androidx.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     // Always download packages if no minimum version given.
49     public static final int DEFAULT_MINIMUM_VERSION = Integer.MAX_VALUE;
50 
51     public static final Parcelable.Creator<PackageDownloadInfo> CREATOR
52             = new Parcelable.Creator<PackageDownloadInfo>() {
53         @Override
54         public PackageDownloadInfo createFromParcel(Parcel in) {
55             return new PackageDownloadInfo(in);
56         }
57 
58         @Override
59         public PackageDownloadInfo[] newArray(int size) {
60             return new PackageDownloadInfo[size];
61         }
62     };
63 
64     /**
65      * Url where the package (.apk) can be downloaded from. {@code null} if there is no download
66      * location specified.
67      */
68     public final String location;
69     /** Cookie header for http request. */
70     @Nullable
71     public final String cookieHeader;
72     /**
73      * One of the following two checksums should be non empty. SHA-256 hash of the
74      * .apk file, or empty array if not used.
75      */
76     public final byte[] packageChecksum;
77     /** SHA-256 hash of the signature in the .apk file, or empty array if not used. */
78     public final byte[] signatureChecksum;
79     /** Minimum supported version code of the downloaded package. */
80     public final int minVersion;
81 
PackageDownloadInfo(Builder builder)82     private PackageDownloadInfo(Builder builder) {
83         location = builder.mLocation;
84         cookieHeader = builder.mCookieHeader;
85         packageChecksum = checkNotNull(builder.mPackageChecksum, "package checksum can't be null");
86         signatureChecksum = checkNotNull(builder.mSignatureChecksum,
87                 "signature checksum can't be null");
88         minVersion = builder.mMinVersion;
89 
90         validateFields();
91     }
92 
PackageDownloadInfo(Parcel in)93     private PackageDownloadInfo(Parcel in) {
94         this(createBuilderFromPersistableBundle(
95                 PersistableBundlable.getPersistableBundleFromParcel(in)));
96     }
97 
validateFields()98     private void validateFields() {
99         if (TextUtils.isEmpty(location)) {
100             throw new IllegalArgumentException("Download location must not be empty.");
101         }
102         if (packageChecksum.length == 0 && signatureChecksum.length == 0) {
103             throw new IllegalArgumentException("Package checksum or signature checksum must be "
104                     + "provided.");
105         }
106     }
107 
fromPersistableBundle(PersistableBundle bundle)108     /* package */ static PackageDownloadInfo fromPersistableBundle(PersistableBundle bundle) {
109         return createBuilderFromPersistableBundle(bundle).build();
110     }
111 
createBuilderFromPersistableBundle(PersistableBundle bundle)112     private static Builder createBuilderFromPersistableBundle(PersistableBundle bundle) {
113         Builder builder = new Builder();
114         builder.setMinVersion(bundle.getInt(EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE));
115         builder.setLocation(bundle.getString(
116                 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION));
117         builder.setCookieHeader(bundle.getString(
118                 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER));
119         builder.setPackageChecksum(StoreUtils.stringToByteArray(bundle.getString(
120                 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM)));
121         builder.setSignatureChecksum(StoreUtils.stringToByteArray(bundle.getString(
122                 EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM)));
123         return builder;
124     }
125 
126     @Override
toPersistableBundle()127     public PersistableBundle toPersistableBundle() {
128         final PersistableBundle bundle = new PersistableBundle();
129         bundle.putInt(EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE,
130                 minVersion);
131         bundle.putString(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION, location);
132         bundle.putString(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER,
133                 cookieHeader);
134         bundle.putString(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM,
135                 StoreUtils.byteArrayToString(packageChecksum));
136         bundle.putString(EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM,
137                 StoreUtils.byteArrayToString(signatureChecksum));
138         return bundle;
139     }
140 
141     public final static class Builder {
142         private String mLocation;
143         private String mCookieHeader;
144         private byte[] mPackageChecksum = DEFAULT_PACKAGE_CHECKSUM;
145         private byte[] mSignatureChecksum = DEFAULT_SIGNATURE_CHECKSUM;
146         private int mMinVersion = DEFAULT_MINIMUM_VERSION;
147 
setLocation(String location)148         public Builder setLocation(String location) {
149             mLocation = location;
150             return this;
151         }
152 
setCookieHeader(String cookieHeader)153         public Builder setCookieHeader(String cookieHeader) {
154             mCookieHeader = cookieHeader;
155             return this;
156         }
157 
setPackageChecksum(byte[] packageChecksum)158         public Builder setPackageChecksum(byte[] packageChecksum) {
159             mPackageChecksum = packageChecksum;
160             return this;
161         }
162 
setSignatureChecksum(byte[] signatureChecksum)163         public Builder setSignatureChecksum(byte[] signatureChecksum) {
164             mSignatureChecksum = signatureChecksum;
165             return this;
166         }
167 
setMinVersion(int minVersion)168         public Builder setMinVersion(int minVersion) {
169             mMinVersion = minVersion;
170             return this;
171         }
172 
build()173         public PackageDownloadInfo build() {
174             return new PackageDownloadInfo(this);
175         }
176 
builder()177         public static Builder builder() {
178             return new Builder();
179         }
180     }
181 }
182